/* * This program converts (mostly) the pseudo-Pascal generated by Tangle to C. * The output depends on many C macros and some postprocessing by other * programs. * * Arguments: * -f: force strict interpretation of semantics of for stmt * (never used with TeX and friends) * -t: special optimizations for tex.p->tex.c * -m: special optimizations for mf.p->mf.c * -c: supply part of the name of the coerce.h file * -h: supply the name of the standard header file * -a: generate ANSI-style function prototypes * * The majority of this program (which includes ptoc.yacc and ptoc.lex) * was written by Tomas Rokicki, with modifications by Tim Morgan. */ #include #include "w2cy.h" #include "w2c.h" #define max_line_length (78) #define ex_32 (2) #define ex_real (3) #define max(a,b) ((a>b)?a:b) int last_tok; int tex = 0, strict_for = 0, mf = 0; char safe_string[80], vvoid [] = "void\0"; char field_list[200]; char last_id[80]; char next_temp[] = "zzzaa"; /* Default names */ char coerce_name[100] = "coerce.h"; char comm_file[100] = "w2c.defines" ; long last_i_num; int ii, l_s; long lower_bound, upper_bound; extern FILE *fopen(); int pf_count = 1; #ifdef ANSI boolean ansi=TRUE; #else boolean ansi=FALSE; #endif char *std_header="w2c-ext.h"; /* Default include filename */ extern int yyleng; extern int yylineno; #define id_char(x) \ ((x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z') || \ (x >= '0' && x <= '9')) void find_next_temp() { next_temp[4]++; if (next_temp[4] > 'z') { next_temp[4] = 'a'; next_temp[3]++; } } /* Normally, output goes to std. These functions switch output on or off, or divert it.*/ int indent = 0; int line_pos=0, str_pos=0; int last_brace = 0; int block_level = 0; boolean want_space = FALSE, str_space = FALSE ; char *sink; FILE *std; FILE *coerce; void normal() { std = stdout; sink = 0; } void silent() { std = 0 ; sink = 0; } /*Divert output to string s */ void to_string(s) char *s; { std = 0 ; sink = s; *s = '\0' ; str_space = FALSE ; str_pos = 0 ; } void new_line() {if (std && (line_pos > 0)) { if ( fputc('\n', std) == EOF) perror( "fputc"); line_pos = 0; want_space = FALSE ; } else if (sink && (str_pos > 0)) { (void) strcat( sink, "\n") ; str_pos = 0; str_space = FALSE ; } } void my_output(s) char *s; { int len = strlen(s); int less_indent = 0; char c = s[len-1], *n ; if (len==0) return ; last_brace = ( c == '}'); if (std) { if ((line_pos + len > max_line_length) || ( *s == '#' && line_pos > 0)) new_line(); if (indent > 1 && (strcmp(s, "case") == 0 || strcmp(s, "default") == 0)) less_indent = 2; if( *s != '#') /*CPP commands must not be indented*/ while (line_pos < indent*2 - less_indent) { if ( fputs(" ", std) == EOF) perror( "fputs"); line_pos += 2; } if (want_space && id_char (*s)) { line_pos += 1; if ( fputc(' ', std) == EOF) perror( "fputc"); } if ( fputs(s, std) == EOF) perror( "fputs"); want_space = id_char(c) ; n = rindex( s, '\n') ; if (n) line_pos = strlen(n) -1 ; else line_pos += len ; } else if (sink) { if ((str_pos + len > max_line_length) || ( *s == '#')) new_line(); /* if (indent > 1 && (strcmp(s, "case") == 0 || strcmp(s, "default") == 0)) less_indent = 2; if( *s != '#') */ /*CPP commands must not be indented*/ /* while (line_pos < indent*2 - less_indent) { (void) strcat ( sink, " ") ; line_pos += 2; } */ if (str_space && id_char (*s)) { str_pos += 1; (void) strcat ( sink, " ") ; } (void) strcat(sink , s); str_space = id_char(c) ; n = rindex( s, '\n') ; if (n) str_pos = strlen(n) -1 ; else str_pos += len ; } } void semicolon() { if (!last_brace) { my_output(";"); new_line(); last_brace = 1; } } void yyerror(s) char *s; { (void) fflush(stdout); (void) fprintf(stderr, " %s\n", s); (void) fprintf(stderr, "Last token - %d\n", last_tok); (void) fprintf(stderr, "Error buffer = %s\n", yytext); (void) fprintf(stderr, "Last id - %s Line number %d\n", last_id, yylineno); ii = search_table(last_id); if (ii == -1) (void) fprintf(stderr, "Not in symbol table!\n"); else switch (sym_table[ii].typ) { case undef_id_tok: (void) fprintf(stderr, "Undefined\n"); break; case var_id_tok: (void) fprintf(stderr, "Variable\n"); break; case const_id_tok: (void) fprintf(stderr, "Constant\n"); break; case type_id_tok: (void) fprintf(stderr, "Type\n"); break; case proc_id_tok: (void) fprintf(stderr, "Procedure\n"); break; case proc_forwd_tok: (void) fprintf(stderr, "Procedure forward\n"); break; case fun_id_tok: (void) fprintf(stderr, "Function\n"); break; case file_id_tok: (void) fprintf(stderr, "File id\n"); break; case fun_forwd_tok: (void) fprintf(stderr, "Function forward\n"); break; default: (void) fprintf(stderr, "Unknown!\n"); break; } (void) fprintf(stderr, "Next sym free = %d\n", last_sym_used); /* (void) fprintf(stderr, "Mark sym = %d\n", mark_sym_used);*/ (void) fprintf(stderr, "Next string free = %d\n", next_string_free); /* (void) fprintf(stderr, "Mark string = %d\n", mark_string_free);*/ } /*Other error messages*/ void err_mes(s) char *s ; { (void) fprintf(stderr, "error: %s line number %d\n", s, yylineno); } /* Managing the table of identifiers. The ids themselves are stored in strings. They are found via the hash table hash_list. If ss is an id, then hash_list[hash(ss)] points to the beginning of a list of ids in sym_table. This list contains all ids with the same hash, linked via their next fields. last_sym_used (previously mis-named next_sym_free) addresses the latest used place in sym_table. */ #define max_strings (20000) #define hash_prime (101) #define sym_table_size (3000) #define max_stack (100) char strings[max_strings]; int hash_list[hash_prime]; short sym_stack[max_stack], string_stack[max_stack]; int depth = 0 ; #ifdef MS_DOS struct sym_entry huge sym_table[sym_table_size]; #else struct sym_entry sym_table[sym_table_size]; #endif int last_sym_used = 0, next_string_free = 0; int hash(id) char *id; { register int i = 0, j; for (j = 0; id[j] != 0; j++) i = (i + i + id[j]) % hash_prime; return (i); } /*Find the hash code and run along its linked list*/ int search_table(id) char *id; { int ptr; ptr = hash_list[hash(id)]; while (ptr) { if (strcmp(id, sym_table[ptr].id) == 0) return (ptr); else ptr = sym_table[ptr].next; } return (0); } #define unused (271828) struct sym_entry dummy = { 0, 0, 0, unused, 0, 0, 0, 0, 0, 0, FALSE, FALSE} ; /*Insert the new id at the front of its hash code's linked list. This hides any previous use of the id.*/ int add_to_table(id) char *id; { int h, ptr; h = hash(id); ptr = hash_list[h]; hash_list[h] = (++last_sym_used); sym_table[last_sym_used] = dummy ; sym_table[last_sym_used].next = ptr; sym_table[last_sym_used].val = unused; sym_table[last_sym_used].id = strings + next_string_free; (void) strcpy(strings + next_string_free, id); next_string_free += strlen(id) + 1; return (last_sym_used); } /*Mark all current ids as belonging to the previous stack frame*/ void mark() { sym_stack[depth-1] = last_sym_used; string_stack[depth-1] = next_string_free; } /*Push a stack frame*/ void push_stack() { if (depth >= max_stack) { err_mes ("Fatal: stack overflow"); exit(1); } sym_stack[depth] = last_sym_used; string_stack[depth] = next_string_free; depth ++ ; } /*Hide all ids from p to q inclusive. */ void hide_ids( p, q) int p, q; { int h, ptr, n; for (h = 0; h < hash_prime; h++) { ptr = hash_list[h]; while (ptr >= p && ptr <= q) ptr = sym_table[ptr].next; hash_list[h] = ptr; while (ptr) { n=ptr; ptr = sym_table[ptr].next; while (ptr >= p && ptr <= q) ptr = sym_table[ptr].next; sym_table[n].next = ptr ; } } } /*Pop a stack frame*/ void pop_stack() { if (depth == 0) { err_mes ("Fatal: POP at level 0"); exit(1); } depth--; hide_ids( sym_stack[depth] +1, last_sym_used ) ; last_sym_used = sym_stack[depth] ; next_string_free = string_stack[depth] ; } /*Un-hide ids from p to q. Each id goes at the head of its hash code's list. */ void unhide_ids( p, q) int p, q; { int h, n, m; char *i ; for (n = p; n <=q ; n++) { i = sym_table[n].id ; h = add_to_table(i); m = sym_table[h].next ; sym_table[h] = sym_table[n] ; sym_table[h].next = m ; } } /*Mark a proc. as 'forward'. fun points to the proc's name; the formal params go from fun+1 to last_sym_used. They must be hidden for later re-use. */ void forward( fun) int fun ; { sym_table[fun].var_formal = TRUE ; hide_ids( sym_table[fun].val_sym , sym_table[fun].upper_sym); if (sym_table[fun].typ == fun_id_tok) sym_table[fun].typ = fun_forwd_tok ; else if (sym_table[fun].typ == proc_id_tok) sym_table[fun].typ = proc_forwd_tok ; else err_mes( "FORWARD on non-proc") ; mark(); } /*Do this when a forward proc is being defined*/ void un_forward( fun) int fun ; { unhide_ids( sym_table[fun].val_sym, sym_table[fun].upper_sym) ; if (sym_table[fun].typ == fun_forwd_tok) sym_table[fun].typ = fun_id_tok ; else if (sym_table[fun].typ == proc_forwd_tok) sym_table[fun].typ = proc_id_tok ; else err_mes( "FORWARD on non-proc") ; } /*Generate prototype and call macro for function fun. The call macro is needed for some Pascal var parameters; but it is too complicated to decide exactly when it is needed, so we simply use a macro whenever the fun. has parameters.*/ void do_prototype( fun, extrn) int fun ; boolean extrn; { int i, m, n; char *result, *name, z_id[100]; struct sym_entry cur_sym; cur_sym = sym_table[fun] ; m = cur_sym.val_sym ; n = cur_sym.upper_sym ; if (cur_sym.arg_typ) result = cur_sym.arg_typ ; else result = vvoid ; name = cur_sym.id ; if (n==0) /*no parameters*/ strcpy( z_id, name) ; else if ( sprintf( z_id, "z%s", name) == NULL) perror( "sprintf"); /* ANSI style prototype */ if ( fprintf( coerce, "\n#ifdef ANSI \n" ) == EOF) perror( "fprintf"); if ( fprintf( coerce, "%s%s %s(", (extrn)?"extern ":"" , result, z_id) == EOF) perror( "fprintf") ; if (n == 0) { if ( fprintf(coerce, "void") == EOF) perror( "fprintf"); } else { for (i=m; i<=n; i++) { if ( fprintf( coerce, " %s%s", sym_table[i].arg_typ , (sym_table[i].need_var)?"*":"") == EOF) perror( "fprintf"); if (i m) if ( fprintf(coerce, ", ") == EOF) perror( "fprintf") ; cur_sym =sym_table[i] ; if ((cur_sym.top_type==is_int) || (cur_sym.top_type==is_point) || (cur_sym.top_type==is_real) || cur_sym.need_var ) { if ( fprintf(coerce, "(%s%s) %s(%s)", cur_sym.arg_typ, cur_sym.need_var?"*":"", cur_sym.need_var?"&":"", cur_sym.id ) == EOF) perror( "fprintf") ;} else if ( fprintf(coerce, "%s", cur_sym.id ) == EOF) perror( "fprintf") ; } if ( fprintf(coerce, ")\n") == EOF) perror( "fprintf"); } if ( fflush(coerce) == EOF) perror( "fflush"); } /*Write the function header for fun*/ void gen_function_head(fun) int fun ; { int i, m, n; char *result, *name, z_id[100], out_string[300]; struct sym_entry cur_sym; cur_sym = sym_table[fun] ; if ( fflush(std) == EOF) perror( "fflush"); m = cur_sym.val_sym ; n = cur_sym.upper_sym ; if (cur_sym.arg_typ) result = cur_sym.arg_typ ; else result = vvoid ; name = cur_sym.id ; if (n==0) /*no parameters*/ strcpy( z_id, name) ; else if ( sprintf( z_id, "z%s", name) == NULL) perror( "sprintf"); /* This part defines the memory word stuff.*/ if (tex) { if (uses_mem && uses_eqtb){ if ( fprintf(coerce, "#define %s_regmem register memoryword *mem=zmem, *eqtb=zeqtb;\n", my_routine) == EOF) perror( "fprintf");} else if (uses_mem){ if ( fprintf(coerce, "#define %s_regmem register memoryword *mem=zmem;\n", my_routine) == EOF) perror( "fprintf");} else if (uses_eqtb){ if ( fprintf(coerce, "#define %s_regmem register memoryword *eqtb=zeqtb;\n", my_routine) == EOF) perror( "fprintf");} else{ if ( fprintf(coerce, "#define %s_regmem\n", my_routine) == EOF) perror( "fprintf");} } /* This part defines the actual header -- ANSI--*/ new_line(); my_output("\n") ; my_output( "#ifdef ANSI \n"); if ( sprintf( out_string, "%s %s(", result, z_id) == NULL) perror( "sprintf") ; my_output(out_string); if (n) { for (i=m; i<=n; i++) { if ( sprintf( out_string, " %s %s%s%s", sym_table[i].arg_typ, (sym_table[i].need_var)?"*":"" , sym_table[i].id, (i