henk@dutesta.UUCP (Henk Hesselink) (11/18/83)
enjoy!!! CUT AT THE DOTTED LINE AND FEED TO /BIN/SH ------------------------------------------------------------------------ echo x - READ.ME cat > READ.ME <<'!End-Of-READ.ME!' YACC PREPROCESSOR In this directory the sources are included of a very simple, but useful, preprocessor for YACC. The preprocessor accepts an extension of the usual YACC input, generates some code for the proper manipulation of attributes and generates output that is legal input to YACC. A simple example, named example, is included in this directory. The only way to call the preprocessor is prep inputfile outputfile A functional description of the preprocessor can be found in SIGPLAN NOTICES, 18 (10) October 1983. Assembling a runnable version of the preprocessor should give no problems, just run the makefile. There might be a slight problem with identifiernames, our PWB C compiler only uses the first 8 characters. I usually use longer names but the tails of identifiers can differ now and then. Good luck, j van katwijk ..!{decvax,philabs}!mcvax!dutesta!katwijk !End-Of-READ.ME! echo x - ex2 cat > ex2 <<'!End-Of-ex2!' %token ONE %token TWO %token THREE %token FOUR %token FIVE %token SIX %token SEVEN %token EIGHT %token NINE %token DOT %attributes number (^float) %attribute front (^int) %attribute back (^int, float) %attribute fd (|int, ^float) %attribute id (^int) %attribute zero_th_digit (^int) %attribute inc_dig_pos (|int, float, ^int) %% number (^f_val): front (^i_val) = { $f_val = (float) $i_val; } | front (^i_val) DOT back (^p, ffract) = { $f_val = (float) $i_val + $ffract; } ; front (^i_val): id (^d_val) | front (^o_ival) id (^d_val) = { $i_val = 10 * $o_ival + $d_val; } ; back (^pos, ffract): zero_th_digit (^pos1) fd (|pos1, ^val) | back (^o_pos, ofval) inc_dig_pos (|o_pos, ofval, ^npos) fd (|npos, ^val) = { $ffract = $ofval + $val; } ; fd (|pos, ^val): id (^digit_val) = { $val = ( (float) $digit_val) / (power (10, $pos)); } ; zero_th_digit (^pos): = { $pos = 1; } ; inc_dig_pos (|o_pos, dummy, ^n_pos) : = { $n_pos = $o_pos + 1; } | ONE = { $digit_val = 1; } | TWO = { $digit_val = 2; } | THREE = { $digit_val = 3; } | FOUR = { $digit_val = 4; } | FIVE = { $digit_val = 5; } | SIX = { $digit_val = 6; } | SEVEN = { $digit_val = 7; } | EIGHT = { $digit_val = 8; } | NINE = { $digit_val = 9; } ; %% !End-Of-ex2! echo x - example cat > example <<'!End-Of-example!' %token ONE %token TWO %token THREE %token FOUR %token FIVE %token SIX %token SEVEN %token EIGHT %token NINE %token DOT %attributes number (^float) %attribute front (^int) %attribute back (^int, float) %attribute fd (|int, ^float) %attribute id (^int) %attribute zero_th_digit (^int) %attribute inc_dig_pos (|int, float, ^int) %% number (^f_val): front (^i_val) = { $f_val = (float) $i_val; } | front (^i_val) DOT back (^p, ffract) = { $f_val = (float) $i_val + $ffract; } ; front (^i_val): id (^d_val) | front (^o_ival) id (^d_val) = { $i_val = 10 * $o_ival + $d_val; } ; back (^pos, ffract): zero_th_digit (^pos1) fd (|pos1, ^val) | back (^o_pos, ofval) inc_dig_pos (|o_pos, ofval, ^npos) fd (|npos, ^val) = { $ffract = $ofval + $val; } ; fd (|pos, ^val): id (^digit_val) = { $val = ( (float) $digit_val) / (power (10, $pos)); } ; zero_th_digit (^pos): = { $pos = 1; } ; inc_dig_pos (|o_pos, dummy, ^n_pos) : = { $n_pos = $o_pos + 1; } ; id (^digit_val): ONE = { $digit_val = 1; } | TWO = { $digit_val = 2; } | THREE = { $digit_val = 3; } | FOUR = { $digit_val = 4; } | FIVE = { $digit_val = 5; } | SIX = { $digit_val = 6; } | SEVEN = { $digit_val = 7; } | EIGHT = { $digit_val = 8; } | NINE = { $digit_val = 9; } ; %% !End-Of-example! echo x - makefile cat > makefile <<'!End-Of-makefile!' # makefile for yacc preprocesor CFLAGS = -c -O DEBUG = LIBS = MACH = -DPDP11 .c.o: cc $(CFLAGS) $(DEBUG) $< prep: prep.h prep1.o prep2.o prep3.o prep4.o cc -n -o prep prep4.o prep[123].o $(LIBS) size prep !End-Of-makefile! echo x - prep.h cat > prep.h <<'!End-Of-prep.h!' # /* * common structures, definitions and so on */ /* * * J van Katwijk * Delft University of Technology, * Department of Mathematics, * 132 Julianalaan * Delft, The Netherlands * * See for a functional description: * * SIGPLAN NOTICES * October 1983, 18 (10) pp 12 .. 16 */ #define MAXATTR 10 #define PAR_SIZ 10 #define TAGSIZE 3000 #define MAXDEF 20 /* I donot know */ #define NONTERM 200 /* include .../dextern?? */ #define WSTACKSIZE 40 /* arbitrary choice */ #define OUTSTACKSIZE 20 /* idem */ #define NAMESIZE 25 /* idem */ #define FATAL 030 #define WARNING 040 #define AS_LOCAL 010 #define AS_STACK 020 #define LOC_STRING "_L%dL_" struct type_elem { int un_number; /* union field number */ char *type_name; /* type to be united */ }; struct param { int par_no; int direction; /* INPUT or OUTPUT */ struct type_elem *par_desc; }; struct att_def { int i_par, o_par; struct param attributes [MAXATTR]; char *nonterm; char hasdefinition; }; struct stack_elem { char par_name [PAR_SIZ]; /* keep it simple */ struct type_elem *par_def; struct { char how_to_access; int ac_offset; int ac_lab; } access; /* for access function */ }; /* * some token definitions */ #define ENDFILE 0 #define COLON 1 #define SEMI 2 #define BAR 3 #define INPUT 3 /* oh yes !!! */ #define EQ_SYMB 4 #define IDENT 5 #define TERM 6 #define LEFT 7 #define BINARY 8 #define RIGHT 9 #define MARK 10 #define PREC 11 #define LCURL 12 #define START 13 #define TYPE 14 #define UNION 15 #define ATTR_DEF 16 #define COMMA 17 #define LPAR 18 #define RPAR 19 #define OUTPUT 20 #define NUMBER 21 extern FILE *finput, *foutput; extern int lineno; extern int tok; extern char tokname[]; extern char *infile; extern error (); extern struct att_def *lookup (); #define islower(x) ('a' <= x && x <= 'z') #define isupper(x) ('A' <= x && x <= 'Z') #define isdigit(x) ('0' <= x && x <= '9') !End-Of-prep.h! echo x - prep1.c cat > prep1.c <<'!End-Of-prep1.c!' # #include <stdio.h> #include "prep.h" /* * * J van Katwijk * Delft University of Technology, * Department of Mathematics, * 132 Julianalaan * Delft, The Netherlands * * See for a functional description: * * SIGPLAN NOTICES * October 1983, 18 (10) pp 12 .. 16 */ /* * * Some notes: * * Two stacks are maintained, a working stack and a destination stack. The latter one is some coding of the situation to be achieved after the reduction. The working stack is basically used to compute the stack layout at the moment of reduction. During the way up to get there, the stack is used to verify the ordering and typing of the input attributes. At the reductionpoint two cases must be distinguished: - The workstack contains only input attributes, i.e. those attributes inherited from the lhs of the rule In this case the runtime stack will be extended to contain the output attributes of the lhs symbol. The output attributes are made addressable on this stack. No end of reduction code is further been generated. - The workstack contains also output attributes. In order to avoid temporarily sharing of the stack locations, the output parameters of the lhs symbol of the rule are made addressable as ordinary local variables. (These variables are declared with unusual names etc.). At the end of the reduction code the runtime stack is adjusted and the preprocessor generated temp's are stored on the stack. */ /* * rules: * definitie : attr_def symbol [ ( [[|inputdefs]^outputdefs]) ] * * rule : lhs : alternative {|alternative} ; * * * alternative : [ {member} ] [= action] * * member : symbol [ ( [|inputlist][^outputlist]) ] * */ proc_def () /* process a definition */ { register char *curr_def; if (tok != ATTR_DEF) return; /* cannot happen */ tok = gettok (); if (tok != IDENT) error (FATAL, "syntax error in attribute definition"); curr_def = new_def (tokname); tok = gettok (); if (tok != LPAR) return; tok = gettok (); if (tok == INPUT) proc_intypes (curr_def); if (tok == OUTPUT) proc_outtypes (curr_def); if (tok != RPAR) error (FATAL, "syntax error in definition for %s", curr_def -> nonterm); tok = gettok (); return; } proc_intypes (definition) register struct att_def *definition; { register int i = 0; if (tok != INPUT) return; /* cannot happen */ tok = gettok (); while (tok == IDENT) { set_input (definition, tokname); tok = gettok (); if (tok == RPAR) return; if (tok != COMMA) error (FATAL, "syntax error (missing comma) in def %s", definition -> nonterm); tok = gettok (); } if (tok != OUTPUT) error (FATAL, "syntax error (missing ^) def %s", definition -> nonterm); return; } proc_outtypes (definition) register struct att_def *definition; { if (tok != OUTPUT) return; /* cannot happen */ tok = gettok (); while (tok == IDENT) { set_output (definition, tokname); tok = gettok (); if (tok == RPAR) return; if (tok != COMMA) error (FATAL, "syntax error (comma expected) def %s", definition -> nonterm); tok = gettok (); } error (FATAL, "syntax error, identifier expected in def for %s", definition -> nonterm); return; } /* * Now for the rule recorgnition, recall that * the symbols of the rules themselves still * have to be processed by YACC. */ struct att_def *lhs_side () { register int par_i_cnt =0; register int par_o_cnt =0; register struct att_def *lhs_member; if (tok != IDENT) error (FATAL, "syntax error in lhs"); fprintf (foutput,"%s :", tokname); lhs_member = lookup (tokname); tok = gettok (); if (tok == LPAR) { if (lhs_member == 0) error (FATAL, "illegal left hand side %s", tokname); setdefined (lhs_member); tok = gettok (); if (tok != INPUT) goto try_output; tok = gettok (); while (tok == IDENT) { par_i_cnt ++; push (lhs_member, par_i_cnt, tokname); tok = gettok (); if (tok == RPAR) goto lhs_check; if (tok != COMMA) error (FATAL, "syntax error (comma expected) lhs %s", lhs_member -> nonterm); tok = gettok (); } try_output: if (tok != OUTPUT) error (FATAL, "^ expected in lhs %s", lhs_member -> nonterm); tok = gettok (); while (tok == IDENT) { par_o_cnt++; dest_par (lhs_member, par_o_cnt, tokname); tok = gettok (); if (tok == RPAR) goto lhs_check; if (tok != COMMA) error (FATAL, "syntax error (comma expected) lhs %s", lhs_member -> nonterm); tok = gettok (); } lhs_check: if (tok != RPAR) error (FATAL, ") expected, lhs %s", lhs_member -> nonterm); tok = gettok (); } if (par_i_cnt != in_pars (lhs_member) || par_o_cnt != out_pars(lhs_member) ) error (FATAL, "incorrect number parameters for %s", lhs_member -> nonterm); return lhs_member; } rule () { register struct att_def *lhs_def; init_stack (); lhs_def = lhs_side (); if (tok != COLON) error (FATAL, " `:' expected following %s", lhs_def -> nonterm); tok = gettok (); proc_alternative (lhs_def); while (tok == BAR) { fprintf (foutput, "\n |"); re_init_stack (); tok = gettok (); proc_alternative (lhs_def); } if (tok != SEMI) error (FATAL, "`;' expected %s", lhs_def -> nonterm); fprintf (foutput, ";\n"); } proc_alternative (lefthand) register struct stack_elem *lefthand; { while (tok == IDENT) { fprintf (foutput, "%s ", tokname); proc_member (lefthand); } if (tok == EQ_SYMB) { fprintf (foutput, "=\n"); tok = gettok (); cpyact (); tok = gettok (); } else adjust_stack (); } proc_member (ctxt) register struct stack_elem *ctxt; { register int in_index, out_index; register struct att_def *curr_member; if (tok != IDENT) return; /* cannot happen */ curr_member = lookup (tokname); tok = gettok (); if (tok != LPAR) { if (curr_member == (struct att_def *)0) return; if (in_pars (curr_member) + out_pars (curr_member) != 0) error (FATAL, "incorrect number of parameters %s", ctxt -> nonterm); return; } if (curr_member == (struct att_def *)0) /* and tok == ( */ error (FATAL, "parameters with non specified symbol rule %s", ctxt -> nonterm); tok = gettok (); in_index = 0; out_index = 0; if (tok == INPUT) { tok = gettok (); while (tok == IDENT) { in_index++; veri_in (curr_member, in_index, tokname); tok = gettok (); if (tok == RPAR) goto par_check; if (tok != COMMA) error (FATAL, "comma expected (member %s)", curr_member -> nonterm); tok = gettok (); } } if (tok != OUTPUT) error (FATAL, "^ expected (member %s)", curr_member -> nonterm); tok = gettok (); while (tok == IDENT) { out_index++; veri_out (curr_member, out_index, tokname); tok = gettok (); if (tok == RPAR) break; if (tok != COMMA) error (FATAL, "`,' expected (member %s)", curr_member -> nonterm); tok = gettok (); } par_check: if ( (in_pars (curr_member) != in_index) || (out_pars (curr_member) != out_index) ) error (FATAL, "incorrect number of parameters (member %s)", curr_member -> nonterm); if (tok != RPAR) error (FATAL, "`)' expected (member %s)", curr_member -> nonterm); tok = gettok (); } !End-Of-prep1.c! echo x - prep2.c cat > prep2.c <<'!End-Of-prep2.c!' # #include <stdio.h> #include "prep.h" /* * * J van Katwijk * Delft University of Technology, * Department of Mathematics, * 132 Julianalaan * Delft, The Netherlands * * See for a functional description: * * SIGPLAN NOTICES * October 1983, 18 (10) pp 12 .. 16 */ /* * scanning/copying routines for YACC preprocessor * * j van katwijk * */ static char c; static int is_digit (x) register char x; { return '0' <= x && x <= '9'; } static int is_letter(x) register char x; { return ('A' <= x && x <= 'Z') || ('a' <= x && x <= 'z'); } int is_namelem (x) register int x; { return (islower(x) || isupper(x) || c == '_' || c == '.' || c == '$' ); } int gettok () { register int i, base; static int peekline; register int match, reserve; /* : */ begin: reserve = 0; lineno += peekline; peekline = 0; c = getc (finput); while (0 <= c && c <= ' ') { if (c == '\n') lineno++; c = getc (finput); } if (c == '/') /* go for comment */ { lineno += skipcom (); goto begin; } switch (c) { case EOF: return ENDFILE; case ':': return COLON; case ';': return SEMI; case '|': return BAR; case '{': ungetc (c, finput); return (EQ_SYMB); /* action .... */ case '<': /* only for the sake of YACC */ i = 0; while ( (c = getc (finput)) != '>' && c >= 0 && c != '\n') { tokname [i] = c; if (++i >= NAMESIZE) --i; } if (c!= '>') error (FATAL, "unterminated <...> clause"); tokname [i] = '\0'; return (IDENT); case ',': return COMMA; case '^': return OUTPUT; case '=': return EQ_SYMB; case '(': return LPAR; case ')': return RPAR; case '"': case '\'': match = c; tokname [0] = ' '; i = 1; for (;;) { c = getc (finput); if (c == '\n' || c == EOF) error (FATAL, "illegal or missing %c", match); if (c == '\\') { c = getc (finput); tokname [i] = '\\'; if (++i >= NAMESIZE) --i; } else if (c == match) break; tokname [i] = c; if (++i >= NAMESIZE) --i; } break; case '%': case '\\': switch (c = getc (finput)) { case '0': return TERM; case '<': return LEFT; case '2': return (BINARY); case '>': return (RIGHT); case '%': case '\\': return (MARK); case '=': return (PREC); case '{': return (LCURL); default: reserve = 1; } /* bah, johnson falls through, we follow here: */ default: if (isdigit (c)) { i = 0; while (isdigit (c)) { tokname [i] = c; if (++i >= NAMESIZE) --i; c = getc (finput); } ungetc (c, finput); return (NUMBER); } else if (is_namelem (c)) { i = 0; while (is_namelem (c) || is_digit (c)) { tokname [i] = c; if (reserve && isupper(c)) tokname [i] += 'a' - 'A'; if (++i >= NAMESIZE) --i; c = getc (finput); } } else return c; ungetc (c, finput); } /* look for reserved words */ tokname [i] = '\0'; if (reserve) { if (!strcmp (tokname, "term")) return TERM; if (!strcmp (tokname, "token")) return TERM; if (!strcmp (tokname, "left")) return LEFT; if (!strcmp (tokname, "nonassoc")) return BINARY; if (!strcmp (tokname, "binary")) return BINARY; if (!strcmp (tokname, "right")) return RIGHT; if (!strcmp (tokname, "prec")) return RIGHT; if (!strcmp (tokname, "start")) return START; if (!strcmp (tokname, "type")) return TYPE; if (!strcmp (tokname, "union")) return UNION; if (!strcmp (tokname, "attributes")) return ATTR_DEF; if (!strcmp (tokname, "attribute")) return ATTR_DEF; error (FATAL, "non recognized keyword %s", tokname); } return (IDENT); } /* * copy the union * */ cpyunion () { int level, c; fprintf (foutput, "\n# line %d \"%s\"\n", lineno, infile); fprintf (foutput, "%%union"); level = 0; for (;;) { if ((c = getc (finput)) <0 ) error (FATAL, "EOF when parsing %%union"); fprintf (foutput, "%c", c); switch (c) { case '\n': ++lineno; break; case '{': ++level; break; case '}': level--; if (level == 0) return; } } } cpycode () /* copies code between { and } */ { register int c; c = getc (finput); if (c == '\n') { c = getc (finput); lineno ++; } fprintf (foutput, "\\{"); while (c >= 0) { if (c == '\\') if ( (c = getc (finput)) == '}') { fprintf (foutput, "\\}"); return; } else fprintf (foutput, "\\"); if (c == '%') if ( (c = getc (finput)) == '}') { fprintf (foutput, "%}"); return; } else fprintf (foutput, "%"); fprintf (foutput, "%c", c); if (c == '\n') lineno ++; c = getc (finput); } error (FATAL, "error before %%}"); } skipcom () /* guess what */ { register int c; register int i = 0; /* number of lines skipped */ if (getc (finput) != '*') error (FATAL, "illegal comment"); c = getc (finput); while (c != EOF) { while (c == '*') if ( (c = getc (finput)) == '/') return i; if (c == '\n') i++; c = getc (finput); } error (FATAL, "error EOF within comment"); } cpyact () /* copy C action to closing ; or } */ { int brac, c, match, j, s, tok; pref_stackadjust (); brac = 0; loop: c = getc (finput); swt: switch (c) { case ';': if (brac == 0) { post_adjuststack (); fprintf (foutput, "%c", c); return; } goto lcopy; case '{': brac++; goto lcopy; case '$': s = 1; tok = -1; c = getc (finput); if (c == '<') /* type description */ { ungetc (c, finput); if (gettok () != IDENT) error (FATAL, "bad syntax on $<..> clause"); fprintf (foutput, "<%s>", tokname); c = getc (finput); } if (c == '$') { fprintf (foutput, "$$"); goto loop; } if (c == '-') { s = -s; c = getc (finput); } if (isdigit (c)) { j = 0; while (isdigit (c)) { j = j * 10 + c - '0'; c = getc (finput); } j = j * s; fprintf (foutput, "$%d", j); goto swt; } if (is_letter (c)) { ungetc (c, finput); tok = gettok (); if (tok != IDENT) error (FATAL, "illegal $construct"); fprintf (foutput, "%s", address_of(tokname)); goto loop; } fprintf (foutput, "$"); if (s < 0) fprintf (foutput, "-"); goto swt; case '}': if (--brac > 0) goto lcopy; post_adjuststack (); fprintf (foutput, "%c", c); return; case '/': /* look for comment */ fprintf (foutput, "%c", c); c = getc (finput); if (c != '*') goto swt; while (c != EOF) { while (c == '*') { fprintf (foutput, "%c", c); if ( (c = getc (finput)) == '/') goto lcopy; } fprintf (foutput, "%c", c); if (c == '\n') lineno++; c = getc (finput); } error (FATAL, "EOF within comment"); case '\'': match = '\''; goto string; case '"': match = '"'; string: fprintf (foutput, "%c", c); while ( (c = getc (finput)) != EOF) { if (c == '\\') { fprintf (foutput, "%c", c); c = getc (finput); if (c == '\n') lineno ++; } else if (c == match) goto lcopy; else if (c == '\n') error (FATAL, "newline in string or char const"); fprintf (foutput, "%c", c); } error (FATAL, "EOF in string or character constant"); case EOF: error ("action does not terminate"); case '\n': lineno++; goto lcopy; } lcopy: fprintf (foutput, "%c", c); goto loop; } !End-Of-prep2.c! echo x - prep3.c cat > prep3.c <<'!End-Of-prep3.c!' # #include <stdio.h> #include "prep.h" /* * * J van Katwijk * Delft University of Technology, * Department of Mathematics, * 132 Julianalaan * Delft, The Netherlands * * See for a functional description: * * SIGPLAN NOTICES * October 1983, 18 (10) pp 12 .. 16 */ /* * low level data/stack management routines for * YACC preprocessor. * */ /* * tags: */ static char name_array [TAGSIZE]; static char *tag_base = &name_array [0]; static int eq_tags (x, y) register char *x, *y; { while (*x == *y && *x != (char)0 && *y != (char)0) { x++; y++; } return (*x == *y); } char *new_tag (t) register char *t; { register char *l_base = tag_base; while ( (*tag_base = *t) != (char)0) { tag_base ++; t++; } tag_base ++; /* set for next definition */ return l_base; } /* * dealing with types and unions */ struct { int el_cnt; struct type_elem descr [MAXDEF]; } type_descr; /* * somewhere a definition of a union of all * attribute element types is generated: */ print_union () { register int i; register struct type_elem *x; if (type_descr. el_cnt == 0) return; /* nothing */ fprintf (foutput, "\n#ifndef ATT_SIZE\n"); fprintf (foutput, "#define ATT_SIZE 150\n"); fprintf (foutput, "#endif\n"); fprintf (foutput, "\nunion _attr_elem {\n"); for (i = 0; i < type_descr. el_cnt; i++) { x = &type_descr.descr [i]; fprintf (foutput, " %s _t%d;\n", x -> type_name, x -> un_number); } fprintf (foutput, "} _attr_stack [ATT_SIZE];\n"); fprintf (foutput, "union _attr_elem *_ap ="); fprintf (foutput, " &_attr_stack [ATT_SIZE - 1];\n"); } struct type_elem *add_type (t) register char *t; { register int i; register struct type_elem *x, *y; for (i = 0; i < type_descr. el_cnt; i++) { x = &type_descr . descr [i]; if (eq_tags (t, x -> type_name)) return x; } if (type_descr.el_cnt >= MAXDEF) error (FATAL, "too many attribute defs: line %d\n", lineno); x = &type_descr. descr [type_descr. el_cnt]; x -> type_name = new_tag (t); x -> un_number = type_descr. el_cnt ++; return x; } /* * attribute definitions */ struct att_def attrib_defs [NONTERM]; static int ndefs = 0; /* * functions to be defined: * * set_input enter input attrib in def * set_output enter output attrib in def * in_pars number of inpars * out_pars number of outpars * new_def enter new non terminal * lookup look for nonterm. * checkdefs check all attributed symbols to be on lhs * setdefined set non terminal defined as lhs */ setdefined (t) struct att_def *t; { if (t != (char)0) t -> hasdefinition = (char)1; } checkdefs () { register int i; for (i = 0; i < ndefs; i ++) if (attrib_defs [i]. hasdefinition == (char) 0) error (WARNING, "%s not as lhs", attrib_defs [i]. nonterm); } struct att_def *lookup (t) register char *t; { register int i; for (i = 0; i < ndefs; i++) if (eq_tags (t, attrib_defs [i]. nonterm)) return &attrib_defs [i]; return (struct att_def *)0; } struct att_def *new_def (t) register char *t; { register struct att_def *x; if (lookup (t) != (struct att_def *)0) error (FATAL, "double definition line %d\n", lineno); if (ndefs >= NONTERM) error (FATAL, "too much non terminals line %d\n", lineno); x = &attrib_defs [ndefs ++]; x -> i_par = 0; x -> o_par = 0; x -> nonterm = new_tag (t); x -> hasdefinition = (char)0; return x; } set_input (def, typename) register struct att_def *def; register char *typename; { register struct att_def *y; if (def -> i_par >= MAXATTR) error (FATAL, "too many input attribs line %d\n", lineno); def -> i_par++; y = &def -> attributes [def -> i_par]; y -> par_no = def -> i_par; y -> direction = INPUT; y -> par_desc = add_type (typename); } set_output (def, type_name) register struct att_def *def; register char *type_name; { register struct att_def *y; if (def -> i_par + def -> o_par >= MAXATTR) error (FATAL, "too many input/output attr's line %d\n", lineno); def -> o_par++; y = &def -> attributes [def -> i_par + def -> o_par]; y -> par_no = def -> o_par; y -> direction = OUTPUT; y -> par_desc = add_type (type_name); } int in_pars (def) register struct att_def *def; { if (def == (struct att_def *)0) return 0; return def -> i_par; } int out_pars (def) register struct att_def *def; { if (def == (struct att_def *)0) return 0; return def -> o_par; } /* * during the processing of a rule a stack is maintained * for the simulation of the run time behaviour */ struct { int i_top; /* input pars lhs */ int o_top; /* output pars lhs */ int w_top; /* workstack top */ struct stack_elem work_stack [WSTACKSIZE]; struct stack_elem out_stack [OUTSTACKSIZE]; } workstack; /* * * functions available during processing a rule: * * * init_stack (); * * push (def, cnt, tag); /* lhs input param * dest_par (def, cnt, tag) /* lhs output param * * veri_in (member, parno, tag); * veri_out(member, parnp, tag); * * address_of (tag) /* map into a string used for C * * pref_stackadjust (); /* code for stack adjustment * post_stackadjust (); /* code for stack adjustment */ init_stack () { workstack. i_top = 0; workstack. o_top = 0; workstack. w_top = 0; } re_init_stack () { workstack. w_top = workstack. i_top; } cp_tag (x, y, cnt) register char *x, *y; register int cnt; { while (--cnt >= 0) *y++ = *x++; } struct type_elem *get_i_type (def, parno) register struct att_def *def; register int parno; { if (parno > def -> i_par) error (FATAL, "too high input param for %s", def -> nonterm); return (def -> attributes [parno].par_desc); } struct type_elem *get_o_type (def, parno) register struct att_def *def; register int parno; { if (parno > def -> o_par) error (FATAL, "too high output param number for %s", def -> nonterm); return (def -> attributes [def -> i_par + parno]. par_desc); } push (def, parno, tag) register struct att_def *def; register char *tag; int parno; { register struct stack_elem *x; if (workstack. i_top ++ >= WSTACKSIZE) error (FATAL, "too much attributes on workstack line %d\n", lineno); x = &workstack. work_stack [workstack. i_top]; cp_tag (tag, &x -> par_name [0], PAR_SIZ); x -> par_def = get_i_type (def, parno); workstack. w_top = workstack. i_top; #ifdef DEBUG printf ("push: %s %d %s\n", &x -> par_name [0], workstack. i_top, x -> par_def -> type_name); #endif } dest_par (def, parno, tag) register struct att_def *def; register char *tag; int parno; { register struct stack_elem *x; if (workstack.o_top ++ >= OUTSTACKSIZE) error (FATAL, "too much lhs out attributes line %d\n", lineno); x = &workstack. out_stack [workstack. o_top]; cp_tag (tag, &x -> par_name [0], PAR_SIZ); x -> par_def = get_o_type (def, parno); #ifdef DEBUG printf ("dest_par : %s %d %s\n", x -> par_name, workstack. o_top, x -> par_def -> type_name); #endif } veri_in (def, parno, tag) register struct att_def *def; register char *tag; int parno; { register struct stack_elem *x; x = &workstack. work_stack[ workstack. w_top - in_pars (def) + parno]; if (!eq_tags (x -> par_name, tag)) error (FATAL, "non matching input name %s", tag); #ifdef DEBUG printf ("veri_in: %s at offset %d\n", tag, workstack. w_top - in_pars (def) + parno); #endif } veri_out (def, parno, tag) register struct att_def *def; register char *tag; int parno; { register struct stack_elem *x; if (workstack. w_top++ >= WSTACKSIZE) error (FATAL, "too much attribute values line %d\n", lineno); x = &workstack. work_stack [workstack. w_top]; cp_tag (tag, &x -> par_name [0], PAR_SIZ); x -> par_def = get_o_type (def, parno); #ifdef DEBUG printf ("veri_out: %s %d %s\n", x -> par_name, workstack. w_top, x -> par_def -> type_name); #endif } /* * given the tag of an attribute, translate it into a string * containing the 'C' code to adress the element on the * attribute stack (or the local....) */ struct stack_elem *search_stck (t) register char *t; { register int i; register struct stack_elem *x; for (i=1; i <= workstack. o_top; i++) { x = &workstack. out_stack [i]; #ifdef DEBUG printf ("search: %s\n", &x -> par_name [0]); #endif if (eq_tags (t, x -> par_name)) return x; } /* * now on the input stack */ for (i = workstack. w_top; i > 0; i--) { x = &workstack. work_stack [i]; #ifdef DEBUG printf ("search: %s\n", x -> par_name); #endif if (eq_tags (t, x -> par_name)) return x; } error (FATAL, "definition of attribute %s not found\n", t); } char *address_of (tag) register char *tag; { register struct stack_elem *t; static char s [20]; /* most numbers will do */ t = search_stck (tag); if (t -> access.how_to_access == AS_LOCAL) sprintf (s, LOC_STRING, t -> access. ac_lab); else sprintf (s, "_ap [%d]. _t%d", t -> access. ac_offset, t -> par_def -> un_number); return s; } /* * generate code for stack adjustment and to make * output paramers addressable */ pref_stackadjust () { register struct stack_elem *x; register int i; register int l_top = 0; fprintf (foutput, "{"); if (workstack. i_top == workstack. w_top) { /* no intermediate results, lengthen * the stack */ if (workstack. o_top != 0) fprintf (foutput, " _ap -= %d;\n", workstack. o_top); l_top = workstack. o_top; for (i = workstack. o_top; i >= 1; i--) { x = &workstack. out_stack [i]; x -> access.how_to_access = AS_STACK; x -> access. ac_offset = workstack. o_top - i; } } else /* generate for each output parameter a local */ for (i = 1; i <= workstack. o_top; i++) { x = &workstack. out_stack [i]; x -> access. how_to_access = AS_LOCAL; x -> access.ac_lab = i; fprintf (foutput, " %s ", x -> par_def -> type_name); fprintf (foutput, LOC_STRING, i); fprintf (foutput, ";\n"); } for (i = workstack. w_top; i > 0; i--) { x = &workstack. work_stack [i]; x -> access.how_to_access = AS_STACK; x -> access.ac_offset = l_top + workstack. w_top - i; } } /* * after copying the C actions, we possibly have to adjust * the attribute value stack */ post_adjuststack () { register struct stack_elem *x; register int i; if (workstack. i_top == workstack. w_top) { /* adjustment already doen, no pushing/popping */ fprintf(foutput, "}\n"); } else { /* generate code for adjusting ap */ fprintf (foutput," _ap += %d; \n", workstack. w_top - workstack. i_top); for (i = 1; i <= workstack. o_top; i++) { x = &workstack. out_stack [i]; fprintf (foutput, "--_ap; _ap[0]._t%d = ", x -> par_def -> un_number); fprintf (foutput, LOC_STRING, x -> access.ac_lab); fprintf (foutput, ";\n"); } fprintf (foutput, " }\n"); } } /* * no yacc actions specified, verify the work/output stack, * adjust if necessary */ adjust_stack () { register int diff; register int i; diff = workstack. w_top - workstack. i_top - workstack. o_top; if (diff != 0) { fprintf (foutput, "= {\n"); fprintf (foutput, "_ap += %d; }\n", diff); } if (diff < 0) { error (WARNING, "garbage on extended attribute stack"); return; } for (i = 1; i <= workstack. o_top; i++) { if (workstack. out_stack [workstack. o_top - i + 1]. par_def != workstack. work_stack [workstack. w_top -i + 1]. par_def) error (WARNING, "unequal default transfers %s", workstack. out_stack [i -1]. par_name); } } !End-Of-prep3.c! echo x - prep4.c cat > prep4.c <<'!End-Of-prep4.c!' # #include <stdio.h> #include "prep.h" /* * * J van Katwijk * Delft University of Technology, * Department of Mathematics, * 132 Julianalaan * Delft, The Netherlands * * See for a functional description: * * SIGPLAN NOTICES * October 1983, 18 (10) pp 12 .. 16 */ FILE *finput, *foutput; char *infile; char tokname [NAMESIZE]; int tok; int lineno = 1; /* * process the declaration section of a YACC source */ prep_decls () { for (tok = gettok (); tok != MARK && tok != ENDFILE; ) { switch (tok) { case SEMI: fprintf (foutput, ";\n"); tok = gettok (); break; case START: if ( (tok = gettok ()) != IDENT) error (FATAL, "bad start construct (YACC)"); fprintf (foutput, "%%start %s\n", tokname); tok = gettok (); continue; case TYPE: if ( (tok = gettok ()) != IDENT) error (FATAL, "bad syntax in %%type (YACC)"); fprintf (foutput, "%%typedef %s ", tokname); while (1) { tok = gettok (); switch (tok) { case IDENT: fprintf (foutput, " %s", tokname); continue; case COMMA: fprintf (foutput, " ,"); continue; case SEMI: fprintf (foutput, ";\n"); tok = gettok (); break; default: break; } break; } continue; case ATTR_DEF: proc_def (); continue; case UNION: /* copy the union declaration to output */ cpyunion (); tok = gettok (); continue; case LEFT: case RIGHT: case BINARY: case TERM: fprintf (foutput, "\n"); switch (tok) { case LEFT: fprintf (foutput, " %%left"); break; case RIGHT: fprintf (foutput, " %%right"); break; case BINARY: fprintf (foutput, " %%nonassoc"); break; case TERM: fprintf (foutput, " %%term"); break; } /* get identifiers so defined */ tok = gettok (); if (tok == IDENT) { fprintf (foutput, " %s", tokname); tok = gettok (); } while (1) { switch (tok) { case COMMA: fprintf (foutput, " ,"); tok = gettok (); break; case SEMI: fprintf (foutput, " ;\n"); break; case IDENT: fprintf (foutput, " %s", tokname); tok = gettok (); continue; } break; } continue; case LCURL: cpycode (); tok = gettok (); continue; default: error (FATAL, "syntax error in def part"); } } /* * tok is either MARK or ENDFILE */ if (tok == ENDFILE) error (FATAL, "unexpected EOF before %%"); } /* * the rules, that is easy */ prep_rules () { fprintf (foutput, "\n%%%%\n"); tok = gettok (); while (tok != ENDFILE && tok != MARK) { rule (); tok = gettok (); } } prep_post () { register int c; fprintf (foutput, "\n%%%%\n"); if (tok == MARK) while ( (c = getc (finput)) != EOF) fprintf (foutput, "%c", c); print_union (); /* the attribute type */ fprintf (foutput, "\n /* processed by a YACC preprocessor */ \n"); } /* * temp. main program * * for yacc preprocessor */ error (x, y, z) register int x; register char *y; register int z; { printf ("\n*** error line %d :", lineno); printf (y, z); printf (" ***\n"); if (x == FATAL) exit (1); } main (argc, argv) register char **argv; register int argc; { if (argc != 3) { printf ("usage: prep infile outfile\n"); exit (1); } infile = argv [1]; finput = fopen (infile, "r"); foutput= fopen (argv [2], "w"); if (finput == 0) error (FATAL, "cannot read from %s", infile); if (foutput == 0) error (FATAL, "cannot write to %s", argv[2]); prep_decls (); prep_rules (); prep_post (); checkdefs (); fclose (foutput); } !End-Of-prep4.c! echo x - rec cat > rec <<'!End-Of-rec!' record_type: record_start (^x, y, z, b) field_list (|x, y, z, b) END RECORD = { restore_env ($1, $x); } ; record_start (^x, y, z, b): type_start (^list) IS RECORD = { register ac t, r; t = $list; r = alloc (XRECTYPE); r -> tag = $1; introduce (r); $x = new_env (r); $y = r; $z = r; $b = FALSE; $$ = r; list_intro (t); } ; type_start(^list): type_id = { $list = NULL; /* discriminants */ } | type_id disc_part = { $list = $2; } ; type_id: TYPE IDENT = { $$ = $2; /* keep the tag */ } ; field_spec: subtype_ind opt_expr = { $$ = make_desc ($1, KCOMP, $2); } ; var_part (|y, z, b) : selection (|y, z, b) alternatives (|y, z, b) END CASE SEM_COL; selection (|y, z, b): CASE s_name IS = { register ac t; t = alloc (XDISCR); t -> comp = $2; $z -> dis = t; } ; alternatives (|y, z, b): variant (|y, z, b) | alternatives (|y, z, b) variant (|y, z, b) ; variant (|y, z, b): selector (|y, z, b, ^xx, yy, zz, bb) ARROW field_list (|xx, yy, zz, bb) = { restore_env ($1, $xx); } ; selector (|y, z, b, ^xx, yy, zz, bb): WHEN choices (^others) = { register ac t; if ($bb) warning ("too much alternatives %s", $y -> tag); $b = $others; t = alloc (XVARIANT); introduce (t); t -> varchoice = $2; $xx = new_env (t); $bb = FALSE; $zz = t; $yy = $y; $$ = t; } ; choices (^others): OTHERS = { register ac t = alloc (XRANGE); $$ = t; $others = TRUE; } | choice_list (^last) = { $others = FALSE; } ; choice_list (^last): choice = { $last = $1; } | choice_list (^l2) BAR choice = { $l2 -> next = $3; $last = $3; } ; choice: ls_name (^l1, l2) range_constraint = { $2 -> rangetype = $1; $$ = $2; } | simple_expr = { register ac t; t = alloc (XRANGE); t -> frangeexp = $1; $$ = t; } | range ; !End-Of-rec! -- Henk Hesselink, Delft Univ. of Technology ..!{decvax,philabs}!mcvax!dutesta!henk