home *** CD-ROM | disk | FTP | other *** search
/ The Education Master 1994 (4th Edition) / EDUCATIONS_MASTER_4TH_EDITION.bin / files / progmisc / qparser2 / cskels / skeleval.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-07  |  9.6 KB  |  324 lines

  1. /* (skel)eval.c
  2.  
  3.    Generates a switch statement with simple printing of productions
  4. and production tags.
  5.    We suggest running this the first time through a grammar, then
  6. expanding the switch modules with semantic code.
  7.  
  8. CUSTOMIZATION:
  9.  
  10.    Under vs. 4.7, we recommend supplying all program customization
  11. through grammar defines, rather than modifying this skeleton file.
  12. The goal, of course, is to keep all grammar-specific information in the
  13. grammar, rather than have part of it show up in skeleton files.
  14.   
  15.    You can define a block of text and give it
  16. an arbitrary name in the grammar like this:
  17.  
  18. #begin dummy_name
  19.   <text>
  20. #end   dummy_name
  21.  
  22.   You can then copy the <text> into any of the files
  23. processed by LR1P through a statement of the form
  24.  
  25.   {## begin indent:=4; 
  26.         if (defined(dummy_name)) then write(dummy_name); 
  27.         end; ##}
  28.  
  29.   Any number of <text> lines can be transferred in this way.  The result 
  30. must of course be syntactically correct when combined with this skeleton 
  31. material.  The <text> is arbitrary and may contain comments, conditionals,
  32. defines, etc. as required in your host language.
  33.   'defined' is a built-in function that returns TRUE if the name is
  34. known and FALSE otherwise.  This makes it possible to have several
  35. lines like the above in this file, whether or not you have definitions
  36. for them in the grammar.
  37.   Nothing is written by the 'write(dummy_name)' unless 'dummy_name' has
  38. been declared in the grammar, so you can freely add as many of these as
  39. you think you'll need.
  40.  
  41.   Several of these are provided in this file -- just search for the '{ # #'
  42. codes with your editor to find them.  Here are some suggestions:
  43.   
  44.    1. Add global declarations (see "apply_locals").
  45.  
  46.    2. Extend the symtabtype or semrectype structs.
  47.  
  48.   In any case, you will want to specify semantic code fragments with
  49. certain productions, particularly those you have tagged.  They are
  50. generated along with the production rule (as a comment) by the
  51. generator program found in the 'apply' function.
  52.   */
  53.  
  54. #include <stdio.h>
  55. #include "decl.h"
  56. #include "sets.h"
  57.  
  58. static semrectype *last_root= NULL;
  59.  
  60. /* TOS(n) is the semantics stack pointer 'n' units from the top,
  61.      i.e. 0, 1, ... reading right to left in the production rule */
  62. #define TOS(n) semstack[stackx-(n)]
  63.  
  64. /* ................. */
  65. semrectype *new_sem(semt, symt)
  66.   int semt, symt;
  67. { semrectype *tsemp;
  68.   int tx;
  69.  
  70.   tsemp= (semrectype *) malloc(sizeof(*tsemp));
  71.   tsemp->semt= semt;
  72.   tsemp->symt= symt;
  73.   switch (semt) {
  74.     case IDENT: tsemp->usem.symp= NULL; break;
  75.     case FIXED: tsemp->usem.numval= 0; break;
  76.     case FLOAT: tsemp->usem.rval= 0.0; break;
  77.     case CHAR:
  78.     case STRNG: tsemp->usem.strx= NULL; break;
  79.     /* NOTE: add more cases here if semrectype is extended */
  80.     default:
  81.       for (tx= 0; tx < MAXNRPLEN; tx++)
  82.         tsemp->usem.position0[tx]= NULL;
  83.       break;
  84.     }
  85.   return tsemp;
  86.   }
  87.  
  88. /* ................. */
  89. semrectype *disp_sem(root)
  90.   semrectype *root;
  91. {   /* this isn't used in the basic skeleton system, but should
  92.          be called to free space occupied by a tree.
  93.        NOTE: this does NOT free symbol space -- call CLEARSYM
  94.          at an appropriate place to do that.
  95.        This does NOT set the internal pointers to NULL -- when
  96.          a struct is deallocated from the heap, nothing should
  97.          be changed in it. */
  98.   int tx;
  99.  
  100.   switch (root->semt) {
  101.     case OTHER:
  102.     case SEMERR:
  103.     case IDENT:
  104.     case FIXED:
  105.     case FLOAT:
  106.       break;
  107.     case CHAR:
  108.     case STRNG:
  109.       /* note that all strings in the semantics stack must have 
  110.            been allocated from the heap! */
  111.       if (root->usem.strx) free(root->usem.strx);
  112.       break;
  113.     /* NOTE: add more cases here if semrectype is extended */
  114.     default:
  115.       for (tx= 0; tx < MAXNRPLEN; tx++)
  116.       if (root->usem.position0[tx])
  117.         disp_sem(root->usem.position0[tx]);
  118.       break;
  119.     }
  120.   return NULL;
  121.   }
  122.  
  123. /* ............ */
  124. static int all_null(root, posx)
  125.   semrectype *root;
  126.   int posx;
  127. {
  128.   while (posx < MAXNRPLEN) {
  129.     if (root->usem.position0[posx]) return 0;
  130.     posx++;
  131.     }
  132.   return 1;
  133.   }
  134.  
  135. /* .............. */
  136. static int print_tree1(root, posx, levelset, indent, lines)
  137.   semrectype *root;
  138.   int posx;
  139.   long int *levelset;
  140.   int lines, indent;
  141. { int px;
  142.   void dump_sem();
  143.  
  144.   /* This prints a tree based on 'root' and the 'semt'
  145.         decorations of each node.
  146.      *levelset is interpreted as bits to indicate whether a
  147.         vertical bar is to be brought down or not, must be 0
  148.         on the root call */
  149.   if (indent < 0) indent= 0;
  150. #if DEBUG == 1
  151.   if (lines > SHOWLINES) {
  152.     char rch= resp("  ---SPACE: more, ENTER: return---");
  153.  
  154.     if (rch=='\n') return -1;
  155.     lines= 0;
  156.     }
  157. #endif
  158.   /* the following reports node type and other information */
  159.   for (px= 0; px < indent-1; px++) {
  160.     if ((*levelset >> px) & 1) printf("| ");
  161.     else printf("  ");
  162.     }
  163.   if (posx < 0) posx= 0;
  164.   if (posx >= MAXNRPLEN) posx= MAXNRPLEN-1;
  165.   if (indent) printf("+-%d ", posx+1);
  166.   if (root) switch (root->semt) {
  167.     case IDENT: printf("IDENT: %s", root->usem.symp->sym); break;
  168.     case FIXED: printf("FIXED: %ld", root->usem.numval); break;
  169.     case FLOAT: printf("FLOAT: %lf", root->usem.rval); break;
  170.     case CHAR: printf("CHAR: '%s'", root->usem.strx); break;
  171.     case STRNG: printf("STRNG: '%s'", root->usem.strx); break;
  172.     default:
  173.       if (root->semt > 0 &&
  174.           root->semt <= LAST_SEMTYPE)
  175.         printf("%s", flags[root->semt]);
  176.       else printf("???");
  177.       break;
  178.     }
  179.   printf("\n");
  180.   lines += 1;
  181.  
  182.   /* now start the recursive call on children, if any */
  183.   if (root &&
  184.       root->semt >= GENL_KIND &&
  185.       root->semt <= LAST_SEMTYPE) {
  186.     *levelset |= ((long int) 1 << indent);
  187.     for (px= 0; px < MAXNRPLEN; px++) {
  188.       if (all_null(root, px)) break;  /* nothing to print */
  189.       if (all_null(root, px+1))  /* don't send bars below this one */
  190.         *levelset &= ~((long int) 1 << indent);
  191.       lines= print_tree1(root->usem.position0[px], px, levelset,
  192.                         indent+1, lines);
  193.       }
  194.     }
  195.   return lines;
  196.   }
  197.  
  198. /* ................. */
  199. void print_tree(root)
  200.   semrectype *root;
  201. { long int levelset= 0;
  202.  
  203.   print_tree1(root, 0, &levelset, 0, 0);  /* display tree nodes */
  204.   }
  205.  
  206. {## begin indent:= 0;
  207.       if (defined(eval_functions)) then writeln(eval_functions); end; ##}
  208.  
  209. #if QTREES == 1
  210. /* .................... */
  211. semrectype *make_node(pflag,cstate)
  212.   int pflag;
  213.   int cstate;
  214. { /* allocates a tree node for this thing */
  215.   semrectype *tsemp= new_sem(pflag, USER /* symt */);
  216.   int px= psmx[cstate];
  217.   int count= psmpos[px++];
  218.   int inx= 0;
  219.  
  220.   while (inx<count)
  221.     /* fill in the positions with nonterminals from the semantics stack */
  222.     tsemp->usem.position0[inx++]= TOS(psmpos[px++]);
  223.     /* any remaining positions are NULL thanks to new_sem */
  224.   return tsemp;
  225.   }
  226.  
  227. /* ................. */
  228. semrectype *make_tree(cstate)
  229.   int cstate;
  230. { int pflag= map[cstate];
  231.  
  232.   /* This allocates a new tree root node, or passes along
  233.        a single child node, returning the node's pointer.
  234.      For a unit production with or without a flag, the existing child
  235.        is just returned.  Otherwise, a new node is allocated
  236.        and one or more children attached to it, based on the
  237.        nonterminals in the production's right member. */
  238.  
  239.   if (pflag==0) {  /* no flag */
  240.     if (popno[cstate]==0) return NULL;    /* empty production */
  241.     if (psmpos[psmx[cstate]]==1)   /* one nonterminal */
  242.       return TOS(psmpos[psmx[cstate] + 1]);
  243.     return make_node(GENL_KIND, cstate);
  244.     }
  245.   else return make_node(pflag, cstate);  /* has a flag */
  246.   }
  247. #endif
  248.  
  249. /* ................. */
  250. void init_sem()
  251. {
  252.   /* this is called before the first production is parsed */
  253. {## begin indent:= 2;
  254.       if (defined(init_sem)) then writeln(init_sem); end; ##}
  255.   }
  256.  
  257. /* ................. */
  258. semrectype *apply(cstate)
  259.   int cstate;
  260. { int pflag= map[cstate];
  261.   semrectype *tsemp= NULL;
  262.  
  263. {## begin indent:= 2;
  264.       if (defined(apply_locals)) then writeln(apply_locals); end; ##}
  265.  
  266. #if QTREES == 1
  267.   tsemp= make_tree(cstate);
  268. #else
  269.   tsemp= NULL;
  270. #endif
  271.  
  272.   switch (pflag) {
  273.     case 0:  /* no flag */
  274.       if (popno[cstate]==1) tsemp= TOS(0);  /* pass this through */
  275.       break;
  276.         
  277. {##
  278.   var K, PX: integer;
  279.   begin   { this generates each 'case' with a production rule and
  280.                semantics of some kind }
  281.     indent:=4;
  282.     for k:=ldim(flags) to udim(flags) do begin
  283.       write('case ', flags[k], ':  /* ');
  284.       begin   {print the production as a comment}
  285.         px:=prodx[flag2state[k]];
  286.         write(no_comment(tokens[prods[px]], ' */'), ' -> ');
  287.         px:=px+1;
  288.         if prods[px]=0 then write('<empty>')
  289.         else while prods[px]>0 do begin
  290.           write(no_comment(tokens[prods[px]], ' */'), ' ');
  291.           px:=px+1;
  292.           end;
  293.         writeln('*/');
  294.         indent:= indent+2;
  295.         if (any_semantics) then
  296.           writeln(semantics[k])
  297.         else
  298.           writeln('printf("%s seen\n", ', qstring(flags[k]), ');');
  299.         writeln('break;');
  300.         indent:= indent-2;
  301.         end
  302.       end
  303.     end;
  304.   ##}
  305.     default: {
  306.       char msg[80];
  307.  
  308.       sprintf(msg, "unrecognized PFLAG: %d", pflag);
  309.       error(msg);
  310.       return tsemp;
  311.       }
  312.     }
  313.   return tsemp;
  314.   }
  315.  
  316. /* ............. */
  317. void end_sem()
  318.   /* Semantics conclusion -- called after the GOAL
  319.     production is applied. */
  320. {
  321. {## begin indent:= 2;
  322.       if (defined(end_sem)) then writeln(end_sem); end; ##}
  323.   }
  324.