home *** CD-ROM | disk | FTP | other *** search
/ The Education Master 1994 (4th Edition) / EDUCATIONS_MASTER_4TH_EDITION.bin / files / progmisc / qparser2 / cskels / calct.grm < prev    next >
Encoding:
Text File  |  1993-11-07  |  4.3 KB  |  116 lines

  1.    \  CALCT -- A simple four-function calculator grammar
  2.    \          which allows variable assignments.
  3.    \  Uses QTREES to produce an abstract syntax tree
  4.    \    and later evaluate it with a tree walker
  5.    \  MUST be compiled with QTREES defined
  6.  
  7. \ symtab_union will be placed in the symtabtype struct, under the
  8. \   union classes.
  9. #begin symtab_union
  10. double value;  /* we need a slot to carry a double value associated
  11.                   with an <identifer> */
  12. #end symtab_union
  13.  
  14. \ eval_functions will appear among the global functions in eval.c.
  15. #begin eval_functions
  16.  
  17. /* ............. */
  18. static double eval(root)
  19.   semrectype *root;
  20. /*  function "eval" expects an expression tree in "root", and walks down
  21.    through it.  The return value will always be the computed arithmetic
  22.    value of the expression tree, as should be apparent from the
  23.    structure of this function.  This can be generalized to return a
  24.    struct pointer for something more complex.  Or the tree walk can
  25.    simply be with the purpose of assigning an attribute to an identifier
  26.    in the symbol table.
  27.  We recommend writing a large "eval" function as a separately
  28.    compiled file, rather than in the grammar as here, in order to avoid
  29.    regenerating the parse tables, expanding skeleton files, etc. required
  30.    by the "make" logic. */
  31. {
  32.   switch (root->semt) {
  33.     case PLUS: return eval(root->LEFT) + eval(root->RIGHT);
  34.     case MINUS: return eval(root->LEFT) - eval(root->RIGHT);
  35.     case MPY:  return eval(root->LEFT) * eval(root->RIGHT);
  36.     case DIVIDE: {
  37.       double denominator= eval(root->RIGHT);
  38.  
  39.       if (denominator == 0.0) {
  40.         printf("  ***divide by 0\n");
  41.         return 0.0;
  42.         }
  43.       else return eval(root->LEFT) / denominator;
  44.       }
  45.     case UMINUS: return -eval(root->CHILD);
  46.     case PARENS:
  47.     case INTVAL:
  48.     case REALVAL:
  49.     case VARIABLE: return eval(root->CHILD);
  50.     case IDENT:  return root->usem.symp->usym.value;
  51.     case FIXED:  return (double) root->usem.numval;
  52.     case FLOAT: return root->usem.rval;
  53.     case QUIT: ;
  54.     default:
  55.       printf(" *** eval case %s (%d) not supported\n",
  56.              flags[root->semt], root->semt);
  57.       return 0.0;
  58.     }
  59.   }
  60.  
  61. #end eval_functions
  62.  
  63. \ apply_locals will appear just after the local variable declarations
  64. \   in function apply in eval.c, but before any executables
  65. #begin apply_locals
  66.   double evalue;
  67. #end apply_locals
  68.  
  69. \  GRAMMAR STARTS HERE
  70. \  Each tagged production will get built into a syntax tree for
  71. \  evaluation by function "eval", defined above
  72. \  Untagged single productions are bypassed in the tree and can
  73. \    therefore be ignored.  Terminal tokens, e.g. "+", "/", "(", ")",
  74. \    are NOT assigned a position in the AST.
  75.  
  76. Goal    -> Stmts QUIT <eol> #QUIT
  77. Stmts   -> Stmts Stmt
  78.         -> <empty>
  79. Stmt    -> Expr <eol> #PRTVAL
  80.            {  /* CHILD refers to the "Expr"; <eol> is not put in the tree */
  81.              evalue= eval(tsemp->CHILD);  /* evaluate the expression tree */
  82.              printf("  %lf\n", evalue);
  83.              tsemp= disp_sem(tsemp);
  84.              }
  85.         -> <identifier> := Expr <eol> #ASSIGN1 
  86.            {
  87.              /* RIGHT refers to "Expr", LEFT to "<identifier>".  ":=" and
  88.                 "<eol>" are not put in the tree */
  89.              evalue= eval(tsemp->RIGHT);  /* evaluate Expr tree */
  90.              tsemp->LEFT->usem.symp->usym.value= evalue;  /* the assignment */
  91.              tsemp->LEFT->usem.symp->symt= REALVAR;  /* defined */
  92.              printf("  %lf\n", evalue);
  93.              tsemp= disp_sem(tsemp);
  94.              }
  95.         -> <eol>    \ allow an empty line
  96. Expr    -> Expr + Term #PLUS 
  97.         -> Expr - Term #MINUS 
  98.         -> Term
  99. Term    -> Term * Fact #MPY 
  100.         -> Term / Fact #DIVIDE 
  101.         -> Fact
  102. Fact    -> Primary
  103.         -> - Primary #UMINUS 
  104. Primary -> ( Expr ) #PARENS 
  105.         -> <identifier> #VARIABLE 
  106.           { /* CHILD refers to the "<identifier>" */
  107.             if (tsemp->CHILD->usem.symp->symt != REALVAR) {
  108.               /* name is undefined */
  109.               printf("  %s undefined\n", tsemp->CHILD->usem.symp->sym);
  110.               tsemp->CHILD->usem.symp->symt= REALVAR;  /* define it anyway */
  111.               tsemp->CHILD->usem.symp->usym.value= 0.0;
  112.               }
  113.             }
  114.         -> <real> #REALVAL 
  115.         -> <integer> #INTVAL 
  116.