home *** CD-ROM | disk | FTP | other *** search
- /* (skel)eval.c
-
- Generates a switch statement with simple printing of productions
- and production tags.
- We suggest running this the first time through a grammar, then
- expanding the switch modules with semantic code.
-
- CUSTOMIZATION:
-
- Under vs. 4.7, we recommend supplying all program customization
- through grammar defines, rather than modifying this skeleton file.
- The goal, of course, is to keep all grammar-specific information in the
- grammar, rather than have part of it show up in skeleton files.
-
- You can define a block of text and give it
- an arbitrary name in the grammar like this:
-
- #begin dummy_name
- <text>
- #end dummy_name
-
- You can then copy the <text> into any of the files
- processed by LR1P through a statement of the form
-
- {## begin indent:=4;
- if (defined(dummy_name)) then write(dummy_name);
- end; ##}
-
- Any number of <text> lines can be transferred in this way. The result
- must of course be syntactically correct when combined with this skeleton
- material. The <text> is arbitrary and may contain comments, conditionals,
- defines, etc. as required in your host language.
- 'defined' is a built-in function that returns TRUE if the name is
- known and FALSE otherwise. This makes it possible to have several
- lines like the above in this file, whether or not you have definitions
- for them in the grammar.
- Nothing is written by the 'write(dummy_name)' unless 'dummy_name' has
- been declared in the grammar, so you can freely add as many of these as
- you think you'll need.
-
- Several of these are provided in this file -- just search for the '{ # #'
- codes with your editor to find them. Here are some suggestions:
-
- 1. Add global declarations (see "apply_locals").
-
- 2. Extend the symtabtype or semrectype structs.
-
- In any case, you will want to specify semantic code fragments with
- certain productions, particularly those you have tagged. They are
- generated along with the production rule (as a comment) by the
- generator program found in the 'apply' function.
- */
-
- #include <stdio.h>
- #include "decl.h"
- #include "sets.h"
-
- static semrectype *last_root= NULL;
-
- /* TOS(n) is the semantics stack pointer 'n' units from the top,
- i.e. 0, 1, ... reading right to left in the production rule */
- #define TOS(n) semstack[stackx-(n)]
-
- /* ................. */
- semrectype *new_sem(semt, symt)
- int semt, symt;
- { semrectype *tsemp;
- int tx;
-
- tsemp= (semrectype *) malloc(sizeof(*tsemp));
- tsemp->semt= semt;
- tsemp->symt= symt;
- switch (semt) {
- case IDENT: tsemp->usem.symp= NULL; break;
- case FIXED: tsemp->usem.numval= 0; break;
- case FLOAT: tsemp->usem.rval= 0.0; break;
- case CHAR:
- case STRNG: tsemp->usem.strx= NULL; break;
- /* NOTE: add more cases here if semrectype is extended */
- default:
- for (tx= 0; tx < MAXNRPLEN; tx++)
- tsemp->usem.position0[tx]= NULL;
- break;
- }
- return tsemp;
- }
-
- /* ................. */
- semrectype *disp_sem(root)
- semrectype *root;
- { /* this isn't used in the basic skeleton system, but should
- be called to free space occupied by a tree.
- NOTE: this does NOT free symbol space -- call CLEARSYM
- at an appropriate place to do that.
- This does NOT set the internal pointers to NULL -- when
- a struct is deallocated from the heap, nothing should
- be changed in it. */
- int tx;
-
- switch (root->semt) {
- case OTHER:
- case SEMERR:
- case IDENT:
- case FIXED:
- case FLOAT:
- break;
- case CHAR:
- case STRNG:
- /* note that all strings in the semantics stack must have
- been allocated from the heap! */
- if (root->usem.strx) free(root->usem.strx);
- break;
- /* NOTE: add more cases here if semrectype is extended */
- default:
- for (tx= 0; tx < MAXNRPLEN; tx++)
- if (root->usem.position0[tx])
- disp_sem(root->usem.position0[tx]);
- break;
- }
- return NULL;
- }
-
- /* ............ */
- static int all_null(root, posx)
- semrectype *root;
- int posx;
- {
- while (posx < MAXNRPLEN) {
- if (root->usem.position0[posx]) return 0;
- posx++;
- }
- return 1;
- }
-
- /* .............. */
- static int print_tree1(root, posx, levelset, indent, lines)
- semrectype *root;
- int posx;
- long int *levelset;
- int lines, indent;
- { int px;
- void dump_sem();
-
- /* This prints a tree based on 'root' and the 'semt'
- decorations of each node.
- *levelset is interpreted as bits to indicate whether a
- vertical bar is to be brought down or not, must be 0
- on the root call */
- if (indent < 0) indent= 0;
- #if DEBUG == 1
- if (lines > SHOWLINES) {
- char rch= resp(" ---SPACE: more, ENTER: return---");
-
- if (rch=='\n') return -1;
- lines= 0;
- }
- #endif
- /* the following reports node type and other information */
- for (px= 0; px < indent-1; px++) {
- if ((*levelset >> px) & 1) printf("| ");
- else printf(" ");
- }
- if (posx < 0) posx= 0;
- if (posx >= MAXNRPLEN) posx= MAXNRPLEN-1;
- if (indent) printf("+-%d ", posx+1);
- if (root) switch (root->semt) {
- case IDENT: printf("IDENT: %s", root->usem.symp->sym); break;
- case FIXED: printf("FIXED: %ld", root->usem.numval); break;
- case FLOAT: printf("FLOAT: %lf", root->usem.rval); break;
- case CHAR: printf("CHAR: '%s'", root->usem.strx); break;
- case STRNG: printf("STRNG: '%s'", root->usem.strx); break;
- default:
- if (root->semt > 0 &&
- root->semt <= LAST_SEMTYPE)
- printf("%s", flags[root->semt]);
- else printf("???");
- break;
- }
- printf("\n");
- lines += 1;
-
- /* now start the recursive call on children, if any */
- if (root &&
- root->semt >= GENL_KIND &&
- root->semt <= LAST_SEMTYPE) {
- *levelset |= ((long int) 1 << indent);
- for (px= 0; px < MAXNRPLEN; px++) {
- if (all_null(root, px)) break; /* nothing to print */
- if (all_null(root, px+1)) /* don't send bars below this one */
- *levelset &= ~((long int) 1 << indent);
- lines= print_tree1(root->usem.position0[px], px, levelset,
- indent+1, lines);
- }
- }
- return lines;
- }
-
- /* ................. */
- void print_tree(root)
- semrectype *root;
- { long int levelset= 0;
-
- print_tree1(root, 0, &levelset, 0, 0); /* display tree nodes */
- }
-
- {## begin indent:= 0;
- if (defined(eval_functions)) then writeln(eval_functions); end; ##}
-
- #if QTREES == 1
- /* .................... */
- semrectype *make_node(pflag,cstate)
- int pflag;
- int cstate;
- { /* allocates a tree node for this thing */
- semrectype *tsemp= new_sem(pflag, USER /* symt */);
- int px= psmx[cstate];
- int count= psmpos[px++];
- int inx= 0;
-
- while (inx<count)
- /* fill in the positions with nonterminals from the semantics stack */
- tsemp->usem.position0[inx++]= TOS(psmpos[px++]);
- /* any remaining positions are NULL thanks to new_sem */
- return tsemp;
- }
-
- /* ................. */
- semrectype *make_tree(cstate)
- int cstate;
- { int pflag= map[cstate];
-
- /* This allocates a new tree root node, or passes along
- a single child node, returning the node's pointer.
- For a unit production with or without a flag, the existing child
- is just returned. Otherwise, a new node is allocated
- and one or more children attached to it, based on the
- nonterminals in the production's right member. */
-
- if (pflag==0) { /* no flag */
- if (popno[cstate]==0) return NULL; /* empty production */
- if (psmpos[psmx[cstate]]==1) /* one nonterminal */
- return TOS(psmpos[psmx[cstate] + 1]);
- return make_node(GENL_KIND, cstate);
- }
- else return make_node(pflag, cstate); /* has a flag */
- }
- #endif
-
- /* ................. */
- void init_sem()
- {
- /* this is called before the first production is parsed */
- {## begin indent:= 2;
- if (defined(init_sem)) then writeln(init_sem); end; ##}
- }
-
- /* ................. */
- semrectype *apply(cstate)
- int cstate;
- { int pflag= map[cstate];
- semrectype *tsemp= NULL;
-
- {## begin indent:= 2;
- if (defined(apply_locals)) then writeln(apply_locals); end; ##}
-
- #if QTREES == 1
- tsemp= make_tree(cstate);
- #else
- tsemp= NULL;
- #endif
-
- switch (pflag) {
- case 0: /* no flag */
- if (popno[cstate]==1) tsemp= TOS(0); /* pass this through */
- break;
-
- {##
- var K, PX: integer;
- begin { this generates each 'case' with a production rule and
- semantics of some kind }
- indent:=4;
- for k:=ldim(flags) to udim(flags) do begin
- write('case ', flags[k], ': /* ');
- begin {print the production as a comment}
- px:=prodx[flag2state[k]];
- write(no_comment(tokens[prods[px]], ' */'), ' -> ');
- px:=px+1;
- if prods[px]=0 then write('<empty>')
- else while prods[px]>0 do begin
- write(no_comment(tokens[prods[px]], ' */'), ' ');
- px:=px+1;
- end;
- writeln('*/');
- indent:= indent+2;
- if (any_semantics) then
- writeln(semantics[k])
- else
- writeln('printf("%s seen\n", ', qstring(flags[k]), ');');
- writeln('break;');
- indent:= indent-2;
- end
- end
- end;
- ##}
- default: {
- char msg[80];
-
- sprintf(msg, "unrecognized PFLAG: %d", pflag);
- error(msg);
- return tsemp;
- }
- }
- return tsemp;
- }
-
- /* ............. */
- void end_sem()
- /* Semantics conclusion -- called after the GOAL
- production is applied. */
- {
- {## begin indent:= 2;
- if (defined(end_sem)) then writeln(end_sem); end; ##}
- }