diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/spelchek |
Initial commit
Diffstat (limited to 'support/spelchek')
-rw-r--r-- | support/spelchek/ascii.inf | 10 | ||||
-rw-r--r-- | support/spelchek/english.inf | 32 | ||||
-rw-r--r-- | support/spelchek/german.inf | 59 | ||||
-rw-r--r-- | support/spelchek/heap.c | 72 | ||||
-rw-r--r-- | support/spelchek/heap.h | 18 | ||||
-rw-r--r-- | support/spelchek/library.c | 262 | ||||
-rw-r--r-- | support/spelchek/library.h | 19 | ||||
-rw-r--r-- | support/spelchek/main.c | 321 | ||||
-rw-r--r-- | support/spelchek/parse.c | 769 | ||||
-rw-r--r-- | support/spelchek/parse.h | 18 | ||||
-rw-r--r-- | support/spelchek/texortho.map | 28 | ||||
-rw-r--r-- | support/spelchek/texortho.tex | 308 |
12 files changed, 1916 insertions, 0 deletions
diff --git a/support/spelchek/ascii.inf b/support/spelchek/ascii.inf new file mode 100644 index 0000000000..3c1973f4b5 --- /dev/null +++ b/support/spelchek/ascii.inf @@ -0,0 +1,10 @@ +other \ +other { +other } +other $ +other % +other & +end_of_file + + + diff --git a/support/spelchek/english.inf b/support/spelchek/english.inf new file mode 100644 index 0000000000..80c711c730 --- /dev/null +++ b/support/spelchek/english.inf @@ -0,0 +1,32 @@ +escape_def 2 +- \-@ +/ \quad@ +capital \L@ +capital \AE@ +skipped_command \- +delimiter_command \quad +skipped_command \documentstyle +skipped_command \Huge +delimiter_command \item +delimiter_command \footnote +skipped_environment equation +skipped_environment picture +skipped_environment table +skipped_environment figure +skipped_command \bf +skipped_command \tt +skipped_command \ref +skipped_command \cite +skipped_command \em +skipped_command \it +skipped_command \sc +delimiter_command \section +delimiter_command \subsection +delimiter_command \subsubsection +delimiter_command \index +skipped_command \protect +skipped_command \mbox +end_of_file + + + diff --git a/support/spelchek/german.inf b/support/spelchek/german.inf new file mode 100644 index 0000000000..59fd2d26c5 --- /dev/null +++ b/support/spelchek/german.inf @@ -0,0 +1,59 @@ +letter á
+active "12
+a \"a
+o \"o
+u \"u
+A \"A
+O \"O
+U \"U
+s \ss@
+' \grqq@
+` \glqq@
+< \frqq@
+> \frqq@
+- \-@
+escape_def 3
+3 \ss@
+- \-@
+/ \quad@
+capital \L@
+capital \AE@
+skipped_command \grqq
+skipped_command \glqq
+skipped_command \-
+delimiter_command \quad
+skipped_command \documentstyle
+skipped_command \Huge
+delimiter_command \item
+delimiter_command \footnote
+skipped_environment equation
+skipped_environment picture
+skipped_environment table
+skipped_environment figure
+skipped_command \bf
+skipped_command \tt
+skipped_command \ref
+skipped_command \cite
+skipped_command \em
+skipped_command \it
+skipped_command \sc
+delimiter_command \section
+delimiter_command \subsection
+delimiter_command \subsubsection
+delimiter_command \index
+skipped_command \protect
+skipped_command \mbox
+delimiter_command \paragraph
+delimiter_command \title
+delimiter_command \author
+delimiter_command \cite
+delimiter_command \ref
+delimiter_command \label
+delimiter_command \addcontentsline
+delimiter_command \noindent
+delimiter_command \indent
+delimiter_command \underline
+end_of_file
+
+
+
diff --git a/support/spelchek/heap.c b/support/spelchek/heap.c new file mode 100644 index 0000000000..2d12e52df4 --- /dev/null +++ b/support/spelchek/heap.c @@ -0,0 +1,72 @@ +#include<stdio.h> +#include<stdlib.h> +#include<stddef.h> + +#define align(d) (((d)+(sizeof(void*)-1))&(~(sizeof(void*)-1))) + +#define HEAPIMPLEMENTATION + +typedef struct{ + struct heap_block *first; + struct heap_block *last; + long blocksize; + char *top_of_heap; +}heap; + +struct heap_block{ + struct heap_block *next; + long free; +}; + +#include"heap.h" + +heap *heap_create( long block_size ) /* allocates memory for heap */ +{ + heap *HEAP; + HEAP = ( heap * )malloc( align( block_size) + sizeof(heap)+sizeof(struct heap_block)); + if(NULL == HEAP)return(NULL); + HEAP->first = (struct heap_block*)(HEAP+1); + HEAP->last = HEAP->first; + HEAP->blocksize = align( block_size ); + HEAP->top_of_heap = (char *)(HEAP->last+1); /* next free entry */ + HEAP->first->next = NULL; + HEAP->first->free = block_size; + return(HEAP); +} /* heap_create() */ + + +void *heap_allocate( heap *HEAP, long size ) /* allocates on heap */ +{ + void *help; + if ( HEAP->last->free < size ) + { + if( NULL ==(HEAP->last->next = ( struct heap_block * )malloc( HEAP->blocksize+sizeof(struct heap_block))))return(NULL); + HEAP->last = HEAP->last->next; + HEAP->last->next = NULL; + HEAP->last->free = HEAP->blocksize; + HEAP->top_of_heap = (void *)(HEAP->last+1); /* next free entry */ + } + help = HEAP->top_of_heap; + HEAP->top_of_heap += (align(size) + sizeof(char) -1) / sizeof(char); + HEAP->last->free -= align(size); + return(help); +} /* heap_allocate() */ +void heap_resize( heap *HEAP, void *entry, long size ) +{ + HEAP->last->free += HEAP->top_of_heap - ( (char *)entry + align( size ) ); + HEAP->top_of_heap = (char *)entry + align( size ); +} /* heap_resize() */ + +void heap_delete( heap *HEAP ) +{ + struct heap_block *this, *next; + this = HEAP->first; + free(HEAP); + while(this) + { + next = this->next; + free(this); + this = next; + } /* of while(this) */ +} /* of heap_delete() */ + diff --git a/support/spelchek/heap.h b/support/spelchek/heap.h new file mode 100644 index 0000000000..8e9cd2cf9e --- /dev/null +++ b/support/spelchek/heap.h @@ -0,0 +1,18 @@ +#ifndef HEAP_H +#define HEAP_H + +#ifndef HEAPIMPLEMENTATION +typedef struct {char VAXDUMMY;} heap; +#endif + +heap *heap_create( long block_size ); /* allocates memory for heap */ +void *heap_allocate( heap *HEAP, long size ); /* allocates on heap */ +void heap_resize( heap *HEAP, void *entry, long size ); +void heap_delete( heap *HEAP ); + +#endif + + + + + diff --git a/support/spelchek/library.c b/support/spelchek/library.c new file mode 100644 index 0000000000..45b7673403 --- /dev/null +++ b/support/spelchek/library.c @@ -0,0 +1,262 @@ +#include"heap.h"
+#include<stdlib.h>
+#include<string.h>
+#include<stddef.h>
+#define LIBRARYIMPLEMENTATION
+
+typedef struct{
+ heap *lib_on_which_heap;
+ struct libnode *root;
+ long number_of_entries;
+}library;
+
+struct libnode{
+ struct libnode *left;
+ struct libnode *right;
+ long how_often_occurred;
+ unsigned char *string;
+};
+
+#include "library.h"
+
+static void fill_nodelist( struct libnode *node, struct libnode ***nodelist );
+static int compare( struct libnode **first, struct libnode **second );
+static void fill_tree_hist(struct libnode *node,long tree_hist[],long weight_hist[],long histlenght,long *deepest_branch,int depth);
+static struct libnode *reorder(struct libnode *node, long *depth,long level);
+
+
+library *library_create( long blocksize )
+{
+ library *lib;
+ heap *lib_heap;
+ if( NULL == ( lib_heap = heap_create( blocksize ))) return(NULL);
+ if( NULL == ( lib = heap_allocate( lib_heap, sizeof( library )))) return(NULL);
+ lib->lib_on_which_heap = lib_heap;
+ lib->root = NULL;
+ lib->number_of_entries = 0;
+ return(lib);
+} /* library_create */
+
+void library_delete( library *lib )
+{
+ heap_delete( lib->lib_on_which_heap );
+}
+
+
+int library_read( library *lib, FILE *libfile ) /* reads library */
+{
+ long occurrences;
+ unsigned char string[256];
+
+ while(!feof(libfile))
+ {
+ if (!fscanf(libfile,"%s\t%ld\n", string, &occurrences)) break;
+ if ( occurrences <= 0 ) break;
+ if (!library_enter_entry( lib, string, occurrences ))
+ return(0); /* eintragen hat nicht geklappt */
+
+ } /* while !feof() */
+ return(1);
+}
+
+
+int library_write( library *lib, FILE *libfile )
+{
+ long i;
+ struct libnode **localptr;
+ struct libnode **nodelist;
+ if ( NULL == (nodelist = (struct libnode **)malloc( sizeof(struct libnode *)*lib->number_of_entries))) return(0);
+ localptr = nodelist;
+ fill_nodelist( lib->root, &localptr );
+ qsort( nodelist, lib->number_of_entries, sizeof( struct libnode *), (int (*)(const void *, const void *)) compare );
+/* the qsort is buggy in some libraries, to have a look at the result!! */
+ for(i = 0; i < lib->number_of_entries; i++ )
+ fprintf( libfile, "%s\t%ld\n", nodelist[i]->string, nodelist[i]->how_often_occurred);
+ fprintf( libfile, "end-of-file\t-1\n");
+ free(nodelist);
+ return(1);
+} /* library_write */
+
+static void fill_nodelist( struct libnode *node, struct libnode ***nodelist )
+{
+ if( node )
+ {
+ *((*nodelist)++) = node;
+ fill_nodelist( node->left, nodelist );
+ fill_nodelist( node->right, nodelist );
+ }
+} /* fill_nodelist */
+
+static int compare( struct libnode **first, struct libnode **second )
+{
+ long local;
+
+ local =(*first)->how_often_occurred - (*second)->how_often_occurred;
+ if (local < 0 ) return( 1 );
+ if (local > 0 ) return( -1 );
+ return( 0 );
+}
+
+
+int library_enter_entry( library *lib, const unsigned char *string, long occurrences_so_far )
+{
+ int comp = 1;
+ struct libnode *node;
+ struct libnode **dest;
+
+ if( lib->root == NULL ) /* leere lib */
+ dest = &(lib->root);
+ else
+ {
+ node = lib->root;
+ while( 0 != ( comp = strcmp(node->string,string)))
+ {
+ if ( comp > 0 )
+ {
+ if ( node->left )
+ {
+ node = node->left;
+ continue;
+ }
+ else
+ {
+ dest = &(node->left);
+ break;
+ }
+ }
+ else if( comp < 0 )
+ {
+ if ( node->right )
+ {
+ node = node->right;
+ continue;
+ }
+ else
+ {
+ dest = &(node->right);
+ break;
+ }
+ }
+ }
+ }
+ if ( comp == 0 )
+ {
+ node->how_often_occurred += occurrences_so_far;
+ return( 1 );
+ }
+
+ *dest = heap_allocate( lib->lib_on_which_heap, sizeof(struct libnode)+ strlen(string)+1 );
+ if(!*dest ) return( 0 );
+ (*dest)->left = NULL;
+ (*dest)->right = NULL;
+ (*dest)->string = (unsigned char *)( *dest + 1 ); /* da soll der string hin (hinter libnode) */
+ (*dest)->how_often_occurred = occurrences_so_far;
+ strcpy((*dest)->string, string );
+ lib->number_of_entries++;
+ return( 1 );
+} /* library_enter_entry */
+
+int library_find_entry( library *lib, const unsigned char *string )
+{
+ struct libnode *node;
+ int comp;
+
+ if ( lib->root == NULL ) return( 0 );
+ node = lib->root;
+ while( 0 != ( comp = strcmp(node->string,string)))
+ {
+ if (( comp > 0 )&&(node->left))
+ {
+ node = node->left;
+ continue;
+ }
+ else if(( comp < 0 )&&( node->right ))
+ {
+ node = node->right;
+ continue;
+ }
+ return( 0 );
+ }
+ return( 1 );
+} /* find_entry liefert pointer auf libnode */
+
+
+void library_fill_hist(library *lib,long tree_hist[],long weight_hist[],long histlenght,long *deepest_branch)
+{
+
+ fill_tree_hist( lib->root,tree_hist,weight_hist,histlenght,deepest_branch,0);
+}
+
+static void fill_tree_hist(struct libnode *node,long tree_hist[],long weight_hist[],long histlenght,long *deepest_branch,int depth)
+
+{
+ if (node)
+ {
+ fill_tree_hist(node->left,tree_hist,weight_hist,histlenght,deepest_branch,depth+1);
+ if (depth < histlenght)
+ {
+ tree_hist[depth]++;
+ weight_hist[depth] += node->how_often_occurred;
+ }
+ else
+ tree_hist[histlenght]++;
+ if (depth > *deepest_branch) *deepest_branch = depth;
+ fill_tree_hist(node->right,tree_hist,weight_hist,histlenght,deepest_branch,depth+1);
+ }
+}
+
+int library_reorganize(library *lib)
+{
+ long depth = 0;
+
+ lib->root = reorder(lib->root,&depth,0);
+return((int)lib->root);
+}
+
+static struct libnode *reorder(struct libnode *node, long *depth, long level)
+{
+ if (node)
+ {
+ long left_depth;
+ long right_depth;
+ long newdepth;
+ struct libnode *help;
+
+ help = node;
+ newdepth = *depth;
+ node->left = reorder(node->left, depth, level + 1);
+ left_depth = *depth;
+ *depth = newdepth;
+ node->right = reorder(node->right, depth, level + 1);
+ right_depth = *depth;
+ *depth = right_depth > left_depth ? right_depth : left_depth;
+
+ if (right_depth > left_depth)
+ { /* rechts rotieren */
+ if (node->right)
+ {
+ if (node->right->how_often_occurred == node->how_often_occurred)
+ {
+ help = node->right;
+ node->right = help->left;
+ help->left = node;
+ };
+ };
+ } /* links rotieren */
+ else if (left_depth > right_depth)
+ {
+ if (node->left)
+ {
+ if (node->left->how_often_occurred == node->how_often_occurred)
+ {
+ help = node->left;
+ node->left = help->right;
+ help->right = node;
+ };
+ };
+ };
+ return(help);
+ };
+ if (level > *depth) *depth = level;
+ return(node);
+}
diff --git a/support/spelchek/library.h b/support/spelchek/library.h new file mode 100644 index 0000000000..751f9ff90e --- /dev/null +++ b/support/spelchek/library.h @@ -0,0 +1,19 @@ +#ifndef LIBRARYHEADER
+#define LIBRARYHEADER
+#include<stdio.h>
+
+#ifndef LIBRARYIMPLEMENTATION
+typedef struct {unsigned char VAXDUMMY;} library;
+#endif
+
+library *library_create( long blocksize );
+void library_delete( library *lib );
+int library_read( library *lib, FILE *libfile ); /* reads library */
+int library_enter_entry( library *lib, const unsigned char *string, long occurrences_so_far );
+int library_find_entry( library *lib, const unsigned char *string );
+int library_write( library *lib, FILE *libfile );
+void library_fill_hist( library *lib,long tree_hist[],long weight_hist[],long histlenght,long *deepest_branch);
+int library_reorganize(library *lib);
+#endif
+
+
diff --git a/support/spelchek/main.c b/support/spelchek/main.c new file mode 100644 index 0000000000..c737ebc5c8 --- /dev/null +++ b/support/spelchek/main.c @@ -0,0 +1,321 @@ +#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+
+#include"library.h"
+#include"parse.h"
+
+/* returnwerte:
+-1: option error
+-2: file error
+-3: out of memory */
+#define tolower(c) (('A'<=(c))&&((c)<='Z')? (c)^0x20 : (c))
+#define islower(c) (('a'<=(c))&&((c)<='z'))
+
+int checking = 0, merging = 0, case_sensitive = 0;
+int first_checking = 1;
+int newlibcreate = 1;
+int library_statistics = 0;
+
+
+void print_help(void);
+void lowercase(unsigned char *string);
+void write_statistics( library *mainlib );
+
+
+int main(int argc, const unsigned char *argv[])
+{
+ unsigned char *wort;
+ FILE *texfile, *outfile, *infofile, *newlibfile;
+ library *mainlib, *newlib;
+ const unsigned char *newlibname=NULL, *outputname=NULL, *texfilename = NULL, *infofilename = NULL;
+ unsigned char libnamespace[80], infofilenamespace[] = "TeXortho.inf";
+
+ printf("This is TeXortho, version 1.0, by J.Hannappel and E.Werner \n");
+ printf("written with GNU C, 1991\n\n");
+
+ if ( argc < 3 )
+ {
+ print_help();
+ return(-1);
+ }
+ punctuation_check = 1;
+ new_sentence = 1; /* 1.11.91 */
+ infofilename = infofilenamespace;
+ outfile = stdout;
+ mainlib = library_create( 30000 );
+ /********** parsen der command line */
+
+ {
+ int i;
+ int inputfilefound = 0;
+ int optionfound = 0 , libfilefound = 0;
+ for ( i = 1; i < argc; i++ )
+ {
+ if ( argv[i][0] == '-') /* wir haben eine option */
+ {
+
+ switch( argv[i][1])
+ {
+ case 'h': /* libhist schreiben */
+ library_statistics = 1;
+ break;
+ case 'i':
+ infofilename = argv[++i];
+ break;
+ case 'l': /* name des erzeugten libfiles, default *.lib */
+ newlibname = argv[++i];
+ break;
+ case 'o': /* name des outfiles, default *.out */
+ outputname = argv[++i];
+ break;
+ case 'C': /* case sensitive search */
+ case_sensitive = 1;
+ break;
+ case 'm': /* merge file with lib */
+ optionfound = 1;
+ merging = 1;
+ break;
+ case 'c': /* check file for spelling errors */
+ checking = 1;
+ optionfound = 1;
+ break;
+ case 'p': /* supress check of isolated punctuation chars */
+ punctuation_check = 0;
+ break;
+ case 'n': /* don't create libfile */
+ newlibcreate = 0;
+ break;
+ case 'P': /* supress check of capital letters at the beginnings of sentences */
+ first_checking = 0;
+ break;
+ default:
+ printf("invalid option! aborting...\n" );
+ return(-1);
+ }
+ }
+ else /* wir haben keine option */
+ {
+ if (inputfilefound)
+ {
+ FILE *libfile;
+ libfilefound = 1;
+ if(!(libfile = fopen( argv[i],"r")))
+ {
+ printf("could not open word list %s \n",argv[i]);
+ return(-2);
+ }
+ printf("(%s",argv[i]);
+ if(!library_read( mainlib, libfile ))
+ {
+ printf("could not read word list %s \n",argv[i]);
+ return(-3);
+ }
+ fclose( libfile );
+ printf(")");
+ } /* if inputfilefound */
+ else /* dann isses das texfile */
+ {
+ texfilename = argv[i];
+ inputfilefound = 1;
+ if( newlibname == NULL )
+ {
+ strcpy(libnamespace,argv[i]);
+ newlibname = libnamespace;
+ strcpy(strrchr(newlibname,'.'), ".twl");
+ } /* if newlibname == NULL */
+ }
+ } /* else no option */
+ } /* for i < argc */
+ if( !optionfound || !inputfilefound)
+ {
+ printf("something's missing; aborting...\n");
+ return(-1);
+ }
+ } /* lokale klammer */
+ if( merging && checking )
+ {
+ printf("-c and -m are incompatible options !\n");
+ return(-1);
+ }
+ if( !merging )
+ {
+ if(!( texfile = fopen( texfilename,"r")))
+ {
+ printf("could not open textfile %s \n",texfilename);
+ return(-2);
+ }
+ printf("(%s",texfilename);
+ if ( outputname )
+ {
+ if(!( outfile = fopen( outputname,"w")))
+ {
+ printf("could not open outputfile %s \n",outputname);
+ return(-2);
+ }
+ printf("(%s",outputname);
+ }
+ if(!( infofile = fopen( infofilename,"r")))
+ {
+ printf("could not open infofile %s \n",infofilename);
+ return(-2);
+ }
+ printf( "(%s", infofilename);
+ init_parser( infofile, texfile, outfile ,texfilename);
+ fclose(infofile);
+ printf(")");
+ }
+ if( newlibcreate && !merging ) if( NULL == ( newlib = library_create( 30000 )))
+ {
+ printf("could not create a new word list, probably out of memory...\n");
+ return( -2 );
+ }
+ if( merging )
+ {
+ FILE *newlibfile;
+
+ printf("merging %s to %s ...\n", texfilename, newlibname );
+ if (!(newlibfile = fopen( texfilename, "r")))
+ {
+ printf("could not open word list file %s \n",texfilename);
+ return(-2);
+ }
+ printf("(%s",texfilename);
+ library_read(mainlib, newlibfile );
+ fclose( newlibfile );
+ printf(")");
+ if (!(newlibfile = fopen( newlibname, "w")))
+ {
+ printf("could not open otput library %s \n",newlibname);
+ return(-2);
+ }
+ printf("(%s",newlibname);
+ printf(" reorganizing...\n");
+ library_reorganize(mainlib);
+ printf(" writing...\n");
+ library_write( mainlib, newlibfile );
+ fclose(newlibfile);
+ printf(")\n");
+ if ( library_statistics ) write_statistics( mainlib );
+
+ library_delete( mainlib );
+ return(0);
+ }
+ /*************************** nun bis zum TeXfileende ******************/
+ printf("start parsing...\n");
+
+ while ( wort = next_word( &new_sentence ))
+ {
+ if ( first_checking )
+ if ( new_sentence )
+ {
+ new_sentence = 0;
+ if ( !check_first_char( wort) )
+ fprintf( outfile,"%s:%d: capital letter expected after presumed end of sentence\n",
+ texfilename, zeilennummer );
+ }
+ if( !case_sensitive )lowercase( wort );
+ if(library_find_entry( mainlib, wort ));
+ else
+ {
+ if (newlibcreate) library_enter_entry( newlib, wort, 1 );
+ fprintf(outfile, "%s:%d: unknown %s\n", texfilename, zeilennummer, wort);
+ }
+ }
+ if ( library_statistics ) write_statistics( mainlib );
+ library_delete( mainlib );
+ if (outfile != stdout)
+ {
+ fclose( outfile );
+ printf(")\n");
+ }
+ fclose( texfile );
+ printf(")\n");
+ if( newlibcreate )
+ {
+ if (!(newlibfile = fopen( newlibname, "w")))
+ {
+ printf("could not open output word list %s \n",newlibname);
+ return(-2);
+ }
+ printf("(%s",newlibname);
+ library_write( newlib, newlibfile );
+ fclose(newlibfile);
+ printf(")\n");
+ library_delete( newlib );
+ }
+ return(0);
+} /* end of main */
+
+
+void print_help(void)
+{
+ printf("possible options:\n");
+ printf(" -c\tcheck textfile for errors\n");
+ printf(" -m\tmerge word lists\n");
+ printf("exactly one of the above options is required\n");
+ printf(" -i\tnext parameter is the info file name; default: TeXortho.inf\n");
+ printf(" -l\tnext parameter is the output word list name; default: jobname.twl\n");
+ printf(" -o\tnext parameter is the output file name; default: jobname.out\n");
+ printf(" -C\tcase sensitive search; be sure your library is made for that!\n");
+ printf(" -p\tsupress punctuation check\n");
+ printf(" -P\tsupress check for capital letters at the beginnings of sentences\n");
+ printf(" -n\tdon't create output word list\n");
+ printf(" -h\tdo write a library histogram libhist\n");
+ printf("\nfirst file name is TeX(t) file, the others are word lists\n");
+ printf("for additional help, check the manual\n");
+}
+
+void lowercase( unsigned char *string )
+{
+ while ( *string = tolower(*string) )string++;
+} /* lowercase() */
+
+
+
+void write_statistics( library *mainlib )
+{
+ FILE *newlibfile;
+ if ((newlibfile = fopen( "libhist", "w")))
+ {
+ long tree_hist[250];
+ long weight_hist[250];
+ long deepest_branch;
+ int i;
+ long oldnodes;
+ float treespace;
+
+ printf("writing library statistics on LIBHIST\n");
+ for (i=0;i<250;i++) tree_hist[i] = weight_hist[i] = 0;
+ deepest_branch = 0;
+
+ library_fill_hist( mainlib,tree_hist,weight_hist,249,&deepest_branch );
+
+ fprintf(newlibfile,"deepest branch is %d deep!\n",deepest_branch);
+
+ oldnodes = 0;
+ treespace = 1.0;
+ for ( i = 0; i < (deepest_branch < 249? deepest_branch+1: 250); i++ )
+ {
+ fprintf(newlibfile,"%2d %10d %10d %10d %10.6f %10.3f\n"
+ ,i,tree_hist[i],weight_hist[i],oldnodes - tree_hist[i],
+ (float)tree_hist[i]/treespace,
+ (float)weight_hist[i]/(float)tree_hist[i]);
+ oldnodes = tree_hist[i] * 2;
+ treespace *= 2.0;
+ }
+ fclose(newlibfile);
+ }
+ else
+ printf("could not open word list statistics file....\n");
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/support/spelchek/parse.c b/support/spelchek/parse.c new file mode 100644 index 0000000000..8c21edc94f --- /dev/null +++ b/support/spelchek/parse.c @@ -0,0 +1,769 @@ +#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+#include"heap.h"
+#include"library.h"
+
+#define PARSERIMPLEMENTATION
+#include"parse.h"
+
+#define RINGSIZE 15
+#define MAXSTRING 256
+#define MAXWORT 1022
+#define MODESTACK 100
+#define MINDESTLAENGE 1
+
+#ifdef DEBUG
+#define storemode( mode ) { ringindex++; ringindex %= RINGSIZE; modering[ringindex] = mode; printf("%d ",modering[ringindex]);}
+#else
+#define storemode( mode ) { ringindex++; ringindex %= RINGSIZE; modering[ringindex] = mode;}
+#endif
+
+#define min(a,b) ((a)<(b) ? (a) : (b))
+#define is_a_letter(c) ((('A'<=(c))&&((c)<='Z'))||(('a'<=(c))&&((c)<='z')))
+#define islower( c ) ( ('a'<= ( c ))&&(( c ) <= 'z') )
+#define isdigit( c ) ( ('0'<= ( c ))&&(( c ) <= '9') )
+#define isupper( c ) ( ('A'<= ( c ))&&(( c ) <= 'Z') )
+#define preprevious_mode ( modering[ ringindex > 0 ? ringindex-1 : RINGSIZE-1 ] )
+#define previous_mode ( modering[ ringindex ] )
+#define old_mode( age ) ( modering[ ringindex - age => 0 ? ringindex-age : RINGSIZE + ringindex - age ] )
+
+enum catcode {
+ catcode_escape,
+ catcode_begingroup,
+ catcode_endgroup,
+ catcode_mathshift,
+ catcode_alignmenttab,
+ catcode_endofline,
+ catcode_space,
+ catcode_letter,
+ catcode_other,
+ catcode_active,
+ catcode_comment,
+ catcode_ignored,
+ catcode_eof
+};
+
+enum parsemode {
+ no_mode, /* kein mode im mode-ring */
+ common_mode, /* normale buchstaben */
+ escape_mode, /* befehle */
+ parameter_mode, /* untersuchung von environment-parametern */
+ space_mode, /* skippen von leerzeichen */
+ digit_mode, /* behandeln von zahlen (mit dezimalpunkt) */
+ other_mode, /* skippen von others ( z.b. '(' ) */
+ skip_mode, /* $$ werden geskipt und aehnliches */
+ comment_mode, /* behandeln von kommentaren */
+ active_mode, /* untersuchen von active-characters */
+ end_deletion_mode /* skippen der parameter von \end */
+};
+
+struct token {
+ enum catcode catcode;
+ unsigned char token;
+};
+
+
+struct active_expansion{
+ unsigned char of_what;
+ unsigned char *what;
+};
+
+
+struct active_definition{
+ struct active_definition *next;
+ unsigned char character;
+ int anzahl;
+ struct active_expansion expansion[1];
+};
+
+
+/* Modulglobale variablen */
+
+static enum parsemode modering[RINGSIZE];
+static int ringindex;
+static unsigned char punctuation_chars[50] = ".,:;!?"; /* characters, die hinter sich, aber nicht vor sich ein space wollen */
+static unsigned char textbegingroup_chars[20] = "("; /* characters, die vor sich, aber nicht hinter sich ein space wollen */
+static unsigned char textendgroup_chars[20] = ")"; /* characters, die vor sich, aber nicht hinter sich ein space wollen */
+static unsigned char sentenceend_chars[20]=".!?";
+static int zeilenoffset;
+static struct active_expansion default_expansion;
+static struct active_definition *active_defs;
+static struct active_definition *escape_def;
+static struct active_definition escape_default;
+static heap *active_heap;
+static enum parsemode mode_stack[MODESTACK];
+static enum parsemode *mode; /* pointer auf den mode_stack */
+static struct token actualtoken;
+static FILE *source;
+static FILE *outputfile;
+static const unsigned char *texname;
+static struct token catcodes[256];
+static library *skipped_env, *skipped_com, *delimiter_com;
+static library *weird_capital;
+
+/* prototypen */
+
+static struct token next_token(void);
+static void exit_parser( void );
+
+/* code */
+
+void init_parser(FILE *infofile, FILE *sourcefile, FILE *outfile, const unsigned char *sourcename )
+{
+
+ unsigned char zeile[MAXSTRING];
+ unsigned char keyword[MAXSTRING];
+ outputfile = outfile;
+ source = sourcefile;
+ texname = sourcename;
+ zeilennummer = 1;
+ zeilenoffset = 0;
+
+
+ /* initialisierung des mode-rings auf den jeweils die alten modes kommen */
+
+ for ( ringindex = 0; ringindex < RINGSIZE; ringindex++ )
+ modering[ringindex] = no_mode;
+ ringindex = 0;
+
+ escape_default.anzahl = 1;
+ escape_default.next = NULL;
+ default_expansion.of_what = '-';
+ default_expansion.what = "\\-@";
+ escape_default.expansion[0] = default_expansion;
+
+ skipped_env = library_create( 500 );
+ skipped_com = library_create( 500 );
+ delimiter_com = library_create( 500 );
+ weird_capital = library_create( 500 ); /* 1.11.91 */
+ active_heap = heap_create( 500 );
+ atexit( exit_parser );
+ escape_def = &escape_default;
+ active_defs = NULL;
+ { /* init catcodes */
+ unsigned char c;
+ for ( c = 255; c >= ' '; c-- )
+ {
+ catcodes[c].catcode = catcode_other;
+ catcodes[c].token = c;
+ }
+ for ( c = 1; c < ' '; c++ )
+ catcodes[c].catcode = catcode_ignored;
+
+ catcodes['\\'].catcode = catcode_escape;
+ catcodes['{'].catcode = catcode_begingroup;
+ catcodes['}'].catcode = catcode_endgroup;
+ catcodes['$'].catcode = catcode_mathshift;
+ catcodes['&'].catcode = catcode_alignmenttab;
+ catcodes['\n'].catcode = catcode_endofline;
+ catcodes['\n'].token = '\n';
+ catcodes[' '].catcode = catcode_space;
+ catcodes['\t'].catcode = catcode_space;
+ catcodes['%'].catcode = catcode_comment;
+ for ( c = 'A'; c <= 'Z'; c++ )
+ catcodes[c].catcode = catcode_letter;
+ for ( c = 'a'; c <= 'z'; c++ )
+ catcodes[c].catcode = catcode_letter;
+ catcodes[0].catcode = catcode_eof;
+ } /* init catcodes */
+
+ /* infofile-syntax
+ <keyword>=<string>
+ <keyword> = catcodes / skipped_environment / skipped_commands */
+
+ while( fscanf( infofile, "%s\t%s\n", keyword, zeile ))
+ {
+ unsigned char *zeilepointer;
+ zeilepointer = zeile;
+
+ if (!strcmp(keyword,"escape"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_escape;
+ else if (!strcmp(keyword,"begingroup"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_begingroup;
+ else if (!strcmp(keyword,"endgroup"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_endgroup;
+ else if (!strcmp(keyword,"mathshift"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_mathshift;
+ else if (!strcmp(keyword,"alignmenttab"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_alignmenttab;
+ else if (!strcmp(keyword,"endofline"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_endofline;
+ else if (!strcmp(keyword,"space"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_space;
+ else if (!strcmp(keyword,"letter"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_letter;
+ else if (!strcmp(keyword,"active"))
+ {
+ int i,anzahl;
+ struct active_definition *ad;
+ unsigned char expansion[80];
+ catcodes[*zeilepointer++].catcode = catcode_active;
+ anzahl = atoi( zeilepointer );
+ ad = heap_allocate( active_heap, sizeof( struct active_definition ) + sizeof( struct active_expansion ) * ( anzahl - 1 ));
+ ad->character = *zeile;
+ ad->anzahl = anzahl;
+ ad->next = active_defs;
+ active_defs = ad;
+
+ for ( i = 0; i < anzahl; i++ )
+ {
+ fscanf( infofile, "%c\t%s\n", &( ((ad->expansion)[i]).of_what), expansion );
+ ((ad->expansion)[i]).what = heap_allocate( active_heap, strlen( expansion ) + 1 );
+ strcpy( ((ad->expansion)[i]).what, expansion );
+ } /* for i < anzahl */
+ }
+ else if (!strcmp(keyword,"escape_def"))
+ {
+ int i,anzahl;
+ unsigned char expansion[80];
+ anzahl = atoi( zeilepointer );
+ escape_def = heap_allocate( active_heap, sizeof( struct active_definition ) + sizeof( struct active_expansion ) * ( anzahl - 1 ));
+ escape_def->character = *zeile;
+ escape_def->anzahl = anzahl;
+ escape_def->next = NULL;
+
+ for ( i = 0; i < anzahl; i++ )
+ {
+ fscanf( infofile, "%c\t%s\n", &( ((escape_def->expansion)[i]).of_what), expansion );
+ ((escape_def->expansion)[i]).what = heap_allocate( active_heap, strlen( expansion ) + 1 );
+ strcpy( ((escape_def->expansion)[i]).what, expansion );
+ } /* for i < anzahl */
+ }
+ else if (!strcmp(keyword,"other"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_other;
+ else if (!strcmp(keyword,"ignored"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_ignored;
+ else if (!strcmp(keyword,"comment"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_comment;
+ else if (!strcmp(keyword,"escape"))
+ while ( *zeilepointer ) catcodes[*zeilepointer++].catcode = catcode_escape;
+ else if (!strcmp(keyword,"skipped_command"))
+ library_enter_entry( skipped_com, &zeile[1], 1 );
+ else if (!strcmp(keyword,"punctuation"))
+ strcpy( punctuation_chars, zeile );
+ else if (!strcmp(keyword,"sentenceend"))
+ strcpy( sentenceend_chars, zeile );
+ else if (!strcmp(keyword,"text_begingroup"))
+ strcpy( textbegingroup_chars, zeile );
+ else if (!strcmp(keyword,"text_endgroup"))
+ strcpy( textendgroup_chars, zeile );
+ else if (!strcmp(keyword,"capital")) /* 1.11.91 */
+ library_enter_entry( weird_capital, zeile, 1 );
+ else if (!strcmp(keyword,"skipped_environment"))
+ library_enter_entry( skipped_env, zeile, 1 );
+ else if (!strcmp(keyword,"delimiter_command"))
+ library_enter_entry( delimiter_com, &zeile[1], 1 );
+ else if (!strcmp(keyword,"end_of_file"))break;
+ else
+ printf( "Invalid command %s ignored; check infofile\n\b", keyword);
+ } /* while fgets */
+ actualtoken = next_token();
+ mode = mode_stack+1;
+ *mode = common_mode;
+} /* init_parser */
+
+static struct token next_token(void)
+{
+ unsigned char zeichen;
+ for (;;)
+ {
+ zeichen = getc( source );
+ if (feof(source)) break;
+ if ( zeichen == '\n' ) zeilenoffset++;
+ if (catcodes[zeichen].catcode != catcode_ignored ) return ( catcodes[zeichen] );
+ } /* while zeichen != EOF */
+ return( catcodes[0] );
+} /* next_token */
+
+
+
+unsigned char *next_word( int *end_of_sentence )
+{
+ static unsigned char wortbuffer[MAXWORT + 2];
+ unsigned char *wort;
+ unsigned char *wortzeiger;
+ unsigned char escapebuffer[MAXSTRING];
+ unsigned char *escapezeiger;
+ unsigned char parameterbuffer[MAXSTRING];
+ unsigned char *parameterzeiger;
+ unsigned char endbuffer[MAXSTRING];
+ unsigned char *endzeiger;
+ int wortlaenge = 0;
+
+ escapezeiger = escapebuffer;
+ end_of_sentence = &new_sentence;
+ wort = &wortbuffer[2];
+ wortzeiger = wort;
+ wortlaenge = 0;
+ zeilennummer += zeilenoffset;
+ zeilenoffset = 0;
+
+ while( 1 )
+ {
+ if ( wortzeiger < wort)
+ {
+ wortzeiger = wort;
+ printf("%s:%d:wortunderflow\n",texname, zeilennummer );
+ }
+ if ( wortzeiger >= &wort[MAXWORT-1])
+ {
+ printf("%s:%d:wortoverflow\n",texname, zeilennummer );
+ return(wort);
+ }
+ if ( mode <= mode_stack ) /* stack underflow verhindern */
+ {
+ zeilennummer += zeilenoffset;
+ zeilenoffset = 0;
+ fprintf( outputfile, "%s:%d: stack underflow\n",
+ texname, zeilennummer );
+ mode = mode_stack + 1;
+ *mode = common_mode;
+ };
+ if ( mode >= &mode_stack[ MODESTACK - 1] ) /* stack overflow */
+ {
+ zeilennummer += zeilenoffset;
+ zeilenoffset = 0;
+ fprintf( outputfile, "%s:%d: stack overflow\n",
+ texname, zeilennummer );
+ mode = mode_stack + 1;
+ *mode = common_mode;
+ };
+
+
+ switch( *mode )
+ {
+ case common_mode: /* normale buchstaben */
+ while( actualtoken.catcode == catcode_letter )
+ {
+ if (wortzeiger - wort >= MAXWORT) return(wort);
+ *wortzeiger++ = actualtoken.token;
+ wortlaenge++;
+ actualtoken = next_token();
+ }
+ switch( actualtoken.catcode )
+ {
+ case catcode_escape:
+ storemode( *mode );
+ *++mode = escape_mode; /* mode auf den stack */
+ if (wortzeiger - wort >= MAXWORT) return(wort);
+ *wortzeiger++ = actualtoken.token;
+ actualtoken = next_token();
+ escapezeiger = escapebuffer; /* initialisierung des escapebuffers */
+ break;
+ case catcode_begingroup:
+ storemode( *mode );
+ *++mode = common_mode;
+ actualtoken = next_token();
+ break;
+ case catcode_endgroup:
+ storemode( *mode );
+ --mode;
+ actualtoken = next_token();
+ break;
+ case catcode_mathshift:
+ /* *wortzeiger++ = actualtoken.token; */ /* mshift nicht an wort dran */
+ actualtoken = next_token();
+ break;
+ case catcode_endofline:
+ case catcode_space:
+ storemode( *mode );
+ *++mode = space_mode;
+ *wortzeiger = 0;
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ if ( actualtoken.token == '\n' )
+ {
+ zeilennummer += zeilenoffset;
+ zeilenoffset = 0;
+ }
+ wortzeiger = wort; wortlaenge = 0;
+ break;
+ case catcode_alignmenttab:
+ case catcode_other:
+ storemode( *mode );
+ *++mode = other_mode;
+ *wortzeiger = 0;
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ wortzeiger = wort; wortlaenge = 0;
+ break;
+ case catcode_active:
+ storemode( *mode );
+ *++mode = active_mode;
+ break;
+ case catcode_comment:
+ storemode( *mode );
+ *++mode = comment_mode;
+ break;
+ case catcode_ignored:
+ ;
+ break;
+ case catcode_eof:
+ return( NULL );
+
+ } /* local switch */
+ break;
+
+
+ case escape_mode: /* befehle */
+ switch( actualtoken.catcode )
+ {
+ case catcode_space:
+ *--wortzeiger = 0; /* \\ = \n wortzeiger eins runter, um alten backslash zu tilgen */
+ storemode( *mode );
+ *mode = space_mode;
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ wortzeiger = wort; wortlaenge = 0; /* neues wort anfangen */
+ break;
+ case catcode_escape:
+ *--wortzeiger = 0; /* \\ = \n wortzeiger eins runter, um alten backslash zu tilgen */
+ actualtoken = next_token(); /* naechstes token holen */
+ storemode( *mode );
+ mode--; /* alten mode vom stack holen */
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ wortzeiger = wort; wortlaenge = 0; /* neues wort anfangen */
+ break;
+ case catcode_other:
+ {
+ int i = 0;
+ while ( (((escape_def->expansion)[i]).of_what != actualtoken.token ) && ( i < escape_def->anzahl )) i++;
+
+ /* jetzt haben wir die makroexpansion und schauen ob sie geskippt werden muss */
+
+ if ( i == escape_def->anzahl ) ;
+ else
+ {
+ unsigned char string[80];
+ storemode( *mode );
+ mode--;
+ actualtoken = next_token();
+ strcpy( string,&(((escape_def->expansion)[i]).what[1])); /* kopieren ohne backslash */
+ string[strlen( string )-1] = 0;
+ if( library_find_entry( delimiter_com, string ))
+ {
+ *--wortzeiger = 0; /* eingefuegt 14.11.91 */
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ wortzeiger = wort; wortlaenge = 0;
+ break;
+ }
+ if ( library_find_entry( skipped_com, string ))
+ {
+ *--wortzeiger = 0; /* backslash wegwerfen */
+ }
+ else
+ {
+ wortzeiger--;
+ strcpy (wortzeiger, (( escape_def->expansion)[i] ).what);
+ wortzeiger += strlen((( escape_def->expansion)[i] ).what);
+ wortlaenge++;
+ }
+
+ break;
+ }
+ }
+ case catcode_begingroup: /* zeichen fuer geschweifte klammer auf */
+ case catcode_endgroup: /* zeichen fuer geschweifte klammer zu */
+ case catcode_mathshift: /* dollarzeichen */
+ case catcode_alignmenttab: /* ampersand */
+ case catcode_active:
+ case catcode_comment:
+ *wortzeiger++ = actualtoken.token;
+ actualtoken = next_token();
+ storemode( *mode );
+ mode--;
+ break;
+ case catcode_endofline:
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ *wortzeiger = 0;
+ actualtoken = next_token();
+ break;
+ case catcode_letter:
+ escapezeiger = escapebuffer;
+ do{
+ *escapezeiger++ = actualtoken.token;
+ actualtoken = next_token();
+ }while( actualtoken.catcode == catcode_letter );
+ *escapezeiger = 0;
+ if(!strcmp(escapebuffer,"begin"))
+ {
+ storemode( *mode );
+ *mode = parameter_mode;
+ if( actualtoken.catcode == catcode_comment )
+ {
+ storemode(*mode);
+ *++mode = comment_mode;
+ }
+ break;
+ }
+ if(!strcmp(escapebuffer,"end"))
+ {
+ storemode( *mode );
+ *mode = end_deletion_mode;
+ if( actualtoken.catcode == catcode_comment )
+ {
+ storemode( *mode );
+ *++mode = comment_mode;
+ }
+ break;
+ }
+ if(library_find_entry( delimiter_com, escapebuffer )) /* escapesequenz wortdelimiter (wie \quad)*/
+ {
+ storemode( *mode );
+ mode--;
+ *--wortzeiger = 0;
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ wortzeiger = wort; wortlaenge = 0;
+ }
+ else if ( library_find_entry( skipped_com, escapebuffer ))
+ {
+ storemode( *mode );
+ *mode = space_mode; /* damit der delimiting space ueberlesen wird, eingeb. 20.11.91 */
+ *--wortzeiger = 0;
+ }
+ else
+ {
+ strcpy( wortzeiger,escapebuffer );
+ wortzeiger += ( escapezeiger - escapebuffer );
+ *wortzeiger++ = '@'; /* statt eines leerzeichens in der library fuer z.B. stra\ss e */
+ storemode( *mode );
+ mode--;
+ while ( actualtoken.catcode == catcode_space ) actualtoken = next_token();
+ }
+ break;
+
+ case catcode_ignored:
+ ;
+ break;
+ case catcode_eof:
+ return( NULL );
+
+ } /* local switch */
+
+ break;
+
+ case parameter_mode: /* untersuchung von environment-parametern */
+ parameterzeiger = parameterbuffer;
+ while ( actualtoken.token == '[' )
+ while ( actualtoken.token != ']' )
+ {
+ actualtoken = next_token();
+ if ( actualtoken.catcode == catcode_eof ) return( NULL );
+ }
+ while ( actualtoken.catcode == catcode_begingroup )
+ actualtoken = next_token();
+ while ( actualtoken.catcode == catcode_letter )
+ {
+ *parameterzeiger++ = actualtoken.token;
+ actualtoken = next_token();
+ }
+ *parameterzeiger = 0;
+ if( library_find_entry( skipped_env, parameterbuffer ))
+ {
+ storemode( *mode );
+ *mode = skip_mode;
+ break;
+ }
+ else if ( actualtoken.token == '*' ) actualtoken = next_token();
+ while ( actualtoken.catcode == catcode_endgroup ) actualtoken = next_token();
+ storemode( *mode );
+ mode--;
+ break;
+
+ case other_mode: /* behandlung von others, insbes. interpunktion */
+ if ( punctuation_check )
+ {
+ if ( strchr( punctuation_chars, actualtoken.token ))
+ {
+ unsigned char mishandled_token = actualtoken.token;
+ actualtoken = next_token();
+ if ( actualtoken.catcode == catcode_eof ) return( NULL );
+ if ( strchr(sentenceend_chars, mishandled_token) &&
+ !isdigit( actualtoken.token )) *end_of_sentence = 1;
+ if ( ( actualtoken.catcode != catcode_space )&&
+ ( actualtoken.catcode != catcode_endofline )&&
+ !isdigit( actualtoken.token )&&
+ ( actualtoken.catcode != catcode_alignmenttab)&&
+ ( actualtoken.catcode != catcode_endgroup ))
+ {
+ fprintf(outputfile , "%s:%d: missing space after %c\n",
+ texname, zeilennummer, mishandled_token );
+ }
+ }
+ else /* if actualtoken.token is punctuation_char */
+ {
+ actualtoken = next_token();
+ }
+ }
+ else actualtoken = next_token(); /* if punctuation_check */
+ storemode( *mode );
+ mode--;
+ break;
+
+ case space_mode: /* skippen von leerzeichen */
+ while (( actualtoken.catcode == catcode_space )||( actualtoken.catcode == catcode_endofline))
+ actualtoken = next_token();
+ if ( actualtoken.catcode == catcode_eof ) return( NULL );
+ if ( punctuation_check )
+ if ( strchr( punctuation_chars, actualtoken.token ))
+ fprintf( outputfile , "%s:%d: extra space before %c\n", texname, zeilennummer, actualtoken.token );
+ storemode( *mode );
+ mode--;
+ break;
+ case skip_mode: /* environments{parameterbuffer} werden geskipt */
+ do {
+ do {
+ do {
+ do {
+ do {
+ if( actualtoken.catcode == catcode_eof ) return( NULL );
+ while ( actualtoken.catcode != catcode_escape )actualtoken = next_token();
+ if( actualtoken.catcode == catcode_eof ) return( NULL );
+ actualtoken = next_token();
+ }while( actualtoken.token != 'e' );
+ actualtoken = next_token();
+ }while( actualtoken.token != 'n' );
+ actualtoken = next_token();
+ }while( actualtoken.token != 'd' );
+ actualtoken = next_token();
+ }while( actualtoken.catcode != catcode_begingroup );
+ actualtoken = next_token();
+ endzeiger = endbuffer;
+ while( actualtoken.catcode == catcode_letter )
+ {
+ *endzeiger++ = actualtoken.token;
+ actualtoken = next_token();
+ }
+ *endzeiger = 0;
+ }while( 0 != strcmp( endbuffer,parameterbuffer ));
+ actualtoken = next_token();
+ if( actualtoken.catcode == catcode_eof ) return( NULL );
+ storemode( *mode );
+ mode--;
+ break;
+ case comment_mode: /* behandeln von kommentaren */
+ while ( actualtoken.catcode != catcode_endofline )
+ {
+ actualtoken = next_token();
+ if ( actualtoken.catcode == catcode_eof ) return( NULL );
+ }
+ if ( actualtoken.token == '\n' )
+ {
+ zeilennummer += zeilenoffset;
+ zeilenoffset = 0;
+ }
+ storemode( *mode ); /* 1.11.91 */
+ mode--; /* 1.11.91 */
+ actualtoken = next_token();
+ break;
+
+
+ case active_mode: /* untersuchen von active-characters */
+ {
+ unsigned char wrong_token;
+ struct active_definition *def;
+ int i=0;
+
+ storemode( *mode );
+ mode--;
+ def = active_defs;
+ while ( def->character != actualtoken.token ) def = def->next;
+ actualtoken = next_token();
+ while ( (((def->expansion)[i]).of_what != actualtoken.token ) && ( i < def->anzahl )) i++;
+
+ /* jetzt haben wir die makroexpansion und schauen ob sie geskippt werden muss */
+
+ wrong_token = actualtoken.token;
+ actualtoken = next_token();
+ if ( i == def->anzahl )
+ {
+ fprintf( outputfile, "%s:%d: active %c with unknown parameter %c\n",
+ texname, zeilennummer, def->character,wrong_token );
+ }
+ else
+ {
+ unsigned char string[80];
+ strcpy( string,&(((def->expansion)[i]).what[1])); /* kopieren ohne backslash */
+ string[strlen( string )-1] = 0;
+ if( library_find_entry( delimiter_com, string ))
+ {
+ if ( wortlaenge > MINDESTLAENGE )
+ return( wort );
+ wortzeiger = wort; wortlaenge = 0;
+ }
+ if ( library_find_entry( skipped_com, string ))
+ {
+ ;
+ }
+ else
+ {
+ strcpy (wortzeiger, ((def->expansion)[i]).what);
+ wortzeiger += strlen(((def->expansion)[i]).what);
+ wortlaenge++;
+ }
+ }
+ }
+ break;
+
+
+ case end_deletion_mode:
+ storemode( *mode );
+ mode--;
+ if ( actualtoken.catcode == catcode_begingroup )
+ while ( actualtoken.catcode != catcode_endgroup )
+ {
+ actualtoken = next_token();
+ if ( actualtoken.catcode == catcode_eof ) return ( NULL );
+ }
+ actualtoken = next_token();
+ break;
+ default:
+ ;
+ break;
+ } /* switch */
+ } /* while 1 */
+} /* next_word */
+
+static void exit_parser( void ) /* wirft die nebemlibraries weg */
+{
+ library_delete( skipped_com );
+ library_delete( skipped_env );
+ library_delete( delimiter_com );
+ library_delete( weird_capital );
+ heap_delete( active_heap );
+}
+
+
+int check_first_char( unsigned char *word ) /* prueft den ersten buchstaben */
+{ /* 1 = gross, 0 = klein */
+ unsigned char *hilfspointer;
+ while(word)
+ {
+ unsigned char string[MAXSTRING];
+ while( !is_a_letter( *word ))
+ {
+ if( *word == '\\' )
+ break;
+ word++;
+ }
+ if ( islower( *word ) ) return( 0 );
+ if ( isupper( *word ) ) return( 1 );
+
+ /* wir brauchen noch weird_capital fuer \L@ \AE@ etc. */
+
+ hilfspointer = word;
+ while( ( word )&&( *word != '@' )) /* bis zum @ kopieren */
+ word++; /* von hilfspointer bis word */
+ /* ist der bereich als capital definiert? 1 : continue; */
+ word++; /* affenschwanz mitnehmen */
+ strncpy( string, hilfspointer, min(word - hilfspointer,MAXSTRING) );
+ string[ min(word-hilfspointer,MAXSTRING-1) ] = 0;
+ if ( library_find_entry( weird_capital, string )) return( 1 );
+ }
+ return(0);
+}
diff --git a/support/spelchek/parse.h b/support/spelchek/parse.h new file mode 100644 index 0000000000..e566d32513 --- /dev/null +++ b/support/spelchek/parse.h @@ -0,0 +1,18 @@ +unsigned char *next_word( int *end_of_sentence );
+void init_parser(FILE *infofile, FILE *sourcefile, FILE *outfile, const unsigned char *sourcename );
+int check_first_char( unsigned char *word ); /* 1.11.91 */
+
+#ifndef PARSERIMPLEMENTATION
+extern volatile
+#endif
+int zeilennummer;
+
+#ifndef PARSERIMPLEMENTATION
+extern
+#endif
+int punctuation_check;
+
+#ifndef PARSERIMPLEMENTATION
+extern
+#endif
+int new_sentence;
diff --git a/support/spelchek/texortho.map b/support/spelchek/texortho.map new file mode 100644 index 0000000000..76e11c6cf1 --- /dev/null +++ b/support/spelchek/texortho.map @@ -0,0 +1,28 @@ +
+ Start Stop Length Name Class
+ 00000H 03365H 03366H _TEXT CODE
+ 03366H 03DFFH 00A9AH MAIN_TEXT CODE
+ 03E00H 04034H 00235H HEAP_TEXT CODE
+ 04035H 0481BH 007E7H LIBRARY_TEXT CODE
+ 0481CH 0645DH 01C42H PARSE_TEXT CODE
+ 06460H 06A04H 005A5H E87_PROG CODE
+ 06A10H 06A10H 00000H _FARDATA FAR_DATA
+ 06A10H 06A10H 00000H _OVERLAY_ OVRINFO
+ 06A10H 06A21H 00012H _INIT_ INITDATA
+ 06A22H 06A22H 00000H _INITEND_ INITDATA
+ 06A22H 06A27H 00006H _EXIT_ EXITDATA
+ 06A28H 06A28H 00000H _EXITEND_ EXITDATA
+ 06A30H 06A30H 00000H _1STUB_ STUBSEG
+ 06A30H 07921H 00EF2H _DATA DATA
+ 07922H 07925H 00004H _CVTSEG DATA
+ 07926H 0792BH 00006H _SCNSEG DATA
+ 0792CH 081F5H 008CAH _BSS BSS
+ 081F6H 081F6H 00000H _BSSEND ENDBSS
+ 08200H 0830FH 00110H _STACK STACK
+
+ Origin Group
+ 06A3:0 DGROUP
+ 06A2:0 EGROUP
+ 06A1:0 IGROUP
+
+Program entry point at 0000:0000
diff --git a/support/spelchek/texortho.tex b/support/spelchek/texortho.tex new file mode 100644 index 0000000000..39bb925dc8 --- /dev/null +++ b/support/spelchek/texortho.tex @@ -0,0 +1,308 @@ +\documentstyle{article} +\def\TeXorTho{T\kern-.1667em\lower.5ex\hbox{E}\kern-.1667emX\kern-.4667em\lower1.1667ex\hbox{or}\kern-.5334em\raise.5ex\hbox{T}\kern-.1667em\lower.5ex\hbox{ho}} +\def\TeXortho{T\kern-.1667em\lower.5ex\hbox{E}\kern-.1667emX\kern-.1667em\hbox{or}\kern-.3334em\raise.5ex\hbox{T}\kern-.2em\hbox{ho}} + + + +\begin{document} +\section*{Correcting \TeX{}ts with \TeXorTho } +\TeXortho\ is a program designed for correcting \TeX~files. But with the +right info file it can be made apt for almost any text file. It was written +with GNU C by J\"urgen Hannappel and Eduard Werner, Bonn 1991. + +{\sc Disclaimer:} You are using this program at your own risk. It's your +problem if it crashes your system (and most probably your fault) or writes +over something important on your hard disk etc. + +\TeXortho~is able of checking spelling, correct white space around punctuation +characters and produces output ready to be digested by an EMACS. We've +tried hard to make it as flexible as possible so that active characters +and user-defined macros can be checked as well. + + + +\section{Concepts} +To use \TeXortho{} it is neccesary to understand the basic concepts underlying + its operation. +\TeXortho{} parses a \TeX{}-file into words, + which are sequences of letters seperated by white space or other characters. +These words are then looked up in a word list, + and an error-message is printed into the log-file if the word cannot be found. +So we see that \TeXortho{} has two central parts: + the parser, which parses the \TeX-file into words + and the word list, which contains all knowledge about the spelling of words. + +The \TeXortho{} parser is not only applicable to texts in \TeX{} or \LaTeX{} + format, + but also to almost any other ASCII represented text format. +It can be adapted to your special text format by means of a special + {\em info-file}, + which contains information about which characters are allowed in words, + what sequences of characters are to be considered as commands etc. +The info-file is discussed later on in a special chapter, + but a full understanding will require some knowledge about the \TeX-interna + such as character catcodes or active characters. +Luckily you will not have to alter the info-file at all, + or at most you will have to add the definitions of some rather + seldom occurring commands to it. + +Currently the word list is organized as a binary search tree, + with the frequent words close to the tree root, + so that they can be found as fast as possible +To insure the optimal ordering of words it is neccesary to keep track of + every occurence of every word in as many texts as possible, + which means, + that every time you have produced a text you should check it by the help + of \TeXortho{} and add the new correct spelled words to the standard word + list and update its word frequency information. + +The word lists are kept in files with a default extension of {\tt .twl} + (which stands for {\tt t}ex {\tt w}ord {\tt l}ist). +They are (or should be) sorted in a way which insures an optimal search tree: + sorted by frequency of occurence in descending order, + while groups of equally frequent words are sorted in a way which insures + a good balance of the search tree + (it is not even impossible that for the sake of balance the ordering by + frequency is violated a bit). + +To keep the standard word lists in a proper state the usual usage of + \TeXortho{} should happen in the following steps: + +\begin{enumerate} +\item Process your file (in the accompanying example it will be called + {\tt example.tex}) with the standard word list and infofile.\\ + \verb/TeXortho example.tex -c english.twl -i english.inf/ \\ + This will produce a word list {\tt example.twl} which contains + all the words in your file which are not in the standard word list. + +\item Edit the word list {\tt example.twl} and kill all words that are + misspelled or to strange to be put into the standard library. + +\item Process your file with both the standard word list and your new list of + correct words:\\ + \verb/TeXortho example.tex -c english.twl example.twl -i english.inf -n/ \\ + This will show you most errors in your file, which you should correct + by now. + +\item Process your corrected file with both the standard and the new word list + in order to produce a list of the words which occur in your text + but shall not become part of the standard library:\\ + \verb/TeXortho example.tex -c english.twl example.twl -i english.inf -l spurious.twl/ \\ + This produces a word list {\tt spurious.twl} with all the unwanted words. + +\item Process your file with the word list {\tt spurious.twl} to get a word + list with the common words of your file and correct information + about their frequency:\\ + \verb/TeXortho example.tex -c spurious.twl -i english.inf/ \\ + This will produce a word list {\tt example.twl} consisting of all + words in your file. + +\item Merge the information of your new word list {\tt example.twl} with the + standard word list:\\ + \verb/TeXortho english.twl example.twl -m/ \\ + This will merge the two libraries into a new version of the standard + library, + containing both the new words and the updated frequency information. +\end{enumerate} + + + +\section{Usage and Options} + +\TeXortho{} is invoced both with parameters an with options; + the parameters are the names of the files to be processed or produced. +\TeXortho{} takes any number of filenames as parameters, + their meaning depends on the option \verb/-c/ or \verb/-m/: +With \verb/-m/ you merge word lists and thus all filenames not preceeded by + one of the options \verb/-i/, \verb/-l/ or \verb/-o/ will be interpreted as + one of the word lists to be merged, + while \verb/-c/ tells \TeXortho{} to check the \TeX{}t signified by the first + filename against the word lists contained in the other files. + +Some files of special importance are denoted after one of the options + \verb/-i/, \verb/-l/ and \verb/-o/: after any one of these options a filename + seperated by a blank is exspected. + + +\subsection{{\protect \tt -m} merge word lists} +This option merges word lists together. You must use either -m or -c. + +\subsection{{\protect \tt -c} check text} +The first file name is taken as the input file to be checked, all other +files are word lists. + +\subsection{{\protect \tt -i} info file name} +This option must be followed be an info file name. Default is \verb/TeXortho.inf/ (check the use of uppercase characters on unix systems!). + +\subsection{{\protect \tt -l} output word list name} +This option must be followed by the name of the new word list, + seperated by a blank. +Use this option if you don't like {\tt jobname.twl} as output file name, + which is the default; + jobname is the name of the first file specified, + without extension. + +\subsection{{\protect \tt -o} name} +This option must be followed by the name of a log file, + which will contain all the error messages produced by \TeXortho. +Normally all output goes to stdout. +On unix systems you may use this option to suppress the generation of errormessages by using \verb?/dev/null? as output file. + +\subsection{{\protect \tt -C} case sensitive search} +By default \TeXortho{} converts all the words found in a \TeX{}t into lowercase + prior to looking them up in the word list, + a feature which can be supressed with this option. +It does {\em not} influence the check for capital letters at the beginnings of + new sentences. + +If you want to check case-sensitive, + make sure your library is apt for this. + +\subsection{{\protect \tt -p} supress punctuation check} +This option supresses checking of correct white space around punctuation +characters. + +\subsection{{\protect \tt -P} supress firstcheck} +This option supresses checking of capital letters at the beginnings of sentences. + +\subsection{{\protect \tt -n} don't write output word list} +This supresses the generation of the output word list. + +\subsection{{\protect \tt -h} generate word list histogram} +A file called \verb/libhist/ is generated, + containing some information about the generated word list, + i.e. the depth of the deepest branch of the binary search tree, + and for each level of that tree the number of nodes in it, + the number of nodes weighted by the frequency of occurence of the word, + the number of branches ending there, + the ratio between capacity and filling of that level + and the mean frequency of the words of that level. + +\section{info file} +\subsection{overview} +\subsection{Escape code keywords} +The following keywords affect the handling of \TeX-catcodes. +Normally you won't need them because the \TeX-defaults are already set. + If you use them, +\TeXortho{} will think them handled equally by your TeX-version. +If you don't know anything about them, read the \TeX-book before using these +commands. You can assign values as follows: +\begin{verbatim} +<keyword> <character> +\end{verbatim} +for instance, +\begin{verbatim} +begingroup [ +\end{verbatim} +will force \TeXortho{} to treat a {\tt [} as begin-group character. +(This option defaults to {\tt \{ \} }.) + +Interesting is the keyword {\tt active} which has a different syntax. +Settings should be made as follows: +\begin{verbatim} +active <char><number of possible parameters> +<first parameter> <expansion> +. . . +<last parameter> <expansion> +\end{verbatim} +The usual setting for the german documentstyle shall serve for an example: +\begin{verbatim} +active "12 +a \"a +o \"o +u \"u +A \"A +O \"O +U \"U +s \ss@ +` \glqq@ +' \grqq@ +- \-@ +< \flqq@ +> \frqq@ +\end{verbatim} + +The keyword {\tt escape\_def} has a similar syntax, i.e. +\begin{verbatim} +escape_def <number of different escaped characters> +<first char> <expansion> +. . . +<last char> <expansion> +\end{verbatim} +Again, the usual setting for the german style is used as example: +\begin{verbatim} +escape_def 3 +3 \ss@ +- \-@ +/ \quad@ +\end{verbatim} + + +Possible keywords to assign catcodes are: +\begin{itemize} +\item {\tt escape} +\item {\tt begingroup} +\item {\tt endgroup} +\item {\tt mathshift} +\item {\tt alignmenttab} +\item {\tt endofline} +\item {\tt space} +\item {\tt letter} +\item {\tt active} +\item {\tt other} +\item {\tt ignored} +\item {\tt comment} +\end{itemize} + +\subsection{Making special commands known to \TeXortho} +There is a lot of commands which usually don't occur within words or even +can't occur within words (like \verb/\quad /). Other commands don't make +sense written isolated, like \verb/\v/. Some environments would better +be skipped, since they don't contain words to be checked, like {\tt equation}. +You may want to tell \TeXortho~how each command behaves: + +\begin{itemize} + +\item {\tt skipped\_command} says that the command following will be + skipped over in the \TeX-file, + typicaly commands such as \verb/\protect/ or \verb/\tt/. + +\item {\tt punctuation} is followed by a string consisting of the punctuation + characters; default is \verb",.;:!?". You should not put a blank before such + characters in ordinary text. + \TeXortho{} will also complain if you don't leave white space behind them. + +\item {\tt sentenceend} is followed by a string consisting of the characters + after which you should start with a capital letter. Default is \verb".!?" + +\item {\tt text\_begingroup} is followed by a string of characters before + which a white space should be found and after which there should be none. + Default is \verb"(". + +\item {\tt text\_endgroup} is followed by a string of characters after + which a white space should be found and before which there should be none. + Default is \verb")". + +\item {\tt capital} is followed by a control sequence standing for one capital + letter e.g. \verb/\L@/. + If this sequence requires a delimiter, it must be terminated by @. + Default is none. + +\item {\tt skipped\_environment} is followed by an environment name. + The environment will be skipped by \TeXortho. Default: none. + +\item {\tt delimiter\_command} is followed by a control sequence. + The command will than be taken as a word delimiter like \verb/\quad/. +\item {\tt end\_of\_file} is the terminating line of the info file. +\end{itemize} + +\section{Known bugs and limitations} +\begin{itemize} +\item In the present version it is not possible to process more + than one \TeX-file at once. +\item After a full stop a command like {\tt quad} with no space in front will +cause an error message {\tt missing space after presumed end of sentence}. +\item An erroneous info file might crash the program or even the OS. + So try to set up properly. +\end{itemize} +\end{document} |