home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 40 / IOPROG_40.ISO / SOFT / NETFrameworkSDK.exe / comsdk.cab / samples1.exe / MyC / Src / Parse.cs < prev    next >
Encoding:
Text File  |  2000-06-23  |  25.3 KB  |  1,069 lines

  1. namespace MyC
  2. {
  3. using System;
  4. using System.Text;
  5.  
  6. class Parse
  7. {
  8. private Io io;
  9. private Tok tok;
  10. private Emit emit;
  11. VarList paramvar;
  12. VarList localvar;
  13. VarList staticvar;
  14. int label_count;
  15. private bool mainseen = false;
  16.  
  17. void dataClass(Var e)
  18.   {
  19. #if DEBUG
  20.   Console.WriteLine("dataClass1 token=["+tok+"]\n");
  21. #endif
  22.   int id = tok.getId();
  23.   if (id == Tok.T_EXTERN || id == Tok.T_STATIC || id == Tok.T_AUTO)
  24.     {
  25.     e.setClassId(tok.getId());
  26.     tok.scan();
  27. #if DEBUG
  28.     Console.WriteLine("dataClass2 token=["+tok+"]\n");
  29. #endif
  30.     }
  31.   else
  32.     {
  33.     e.setClassId(Tok.T_DEFCLASS); /* default to current context */
  34.     }
  35.   }
  36.  
  37. void dataType(Var e)
  38.   {
  39.   int id = tok.getId();
  40. #if DEBUG
  41.   Console.WriteLine("dataType1 token=["+tok+"]\n");
  42. #endif
  43.   e.setSign(Tok.T_SIGNED);
  44.   if (id == Tok.T_SIGNED || id == Tok.T_UNSIGNED)
  45.     {
  46.     e.setSign(id);
  47.     tok.scan();
  48.     id = tok.getId();
  49. #if DEBUG
  50.     Console.WriteLine("dataType2 token=["+tok+"]\n");
  51. #endif
  52.     }
  53.   if (id == Tok.T_VOID || id == Tok.T_INT)
  54.     {
  55.     e.setTypeId(id);
  56.     tok.scan();
  57. #if DEBUG
  58.     Console.WriteLine("dataType3 token=["+tok+"]\n");
  59. #endif
  60.     }
  61.   else if (id == Tok.T_LONG)
  62.     Io.ICE("Unhandled type LONG");
  63.   else if (id == Tok.T_CHAR)
  64.     Io.ICE("Unhandled type CHAR");
  65.   else if (id == Tok.T_FLOAT)
  66.     Io.ICE("Unhandled type FLOAT");
  67.   else if (id == Tok.T_DOUBLE)
  68.     Io.ICE("Unhandled type DOUBLE");
  69.   else
  70.     e.setTypeId(Tok.T_DEFTYPE);
  71.   }
  72.  
  73. VarList paramList()
  74.   {
  75.   VarList v;
  76.   tok.scan();
  77.   if (tok.getFirstChar() != '(')
  78.     io.Abort("Expected '('");
  79.  
  80.   v = new VarList();        /* init the param list */
  81.   tok.scan();            /* get the next token */
  82.   while (tok.getFirstChar() != ')')
  83.     {
  84.     Var e = new Var();
  85.     e.setClassId(Tok.T_PARAM);    /* mark this as a parameter */
  86.     dataType(e);        /* get the specified datatype */
  87.     e.setName(tok.getValue()); /* copy the variable name */
  88.     v.add(e);            /* add parameter to param list */
  89.     tok.scan();
  90.     if (tok.getFirstChar() == ',')    /* if more params */
  91.       tok.scan();        /* get the next token */
  92.     }
  93.   tok.scan();        /* move to the next token */
  94.   return v;
  95.   }
  96.  
  97. void outerDecl()
  98.   {
  99.   Var e = new Var();
  100. #if DEBUG
  101.   Console.WriteLine("outerDecl token=["+tok+"]\n");
  102. #endif
  103.  
  104.   CommentHolder();    /* mark the position in insn stream */
  105.  
  106.   dataClass(e);
  107.   dataType(e);
  108.  
  109.   if (io.getNextChar() == '(')
  110.     declFunc(e);
  111.   else
  112.     declOuter(e);
  113.   }
  114.  
  115. void prolog()
  116.   {
  117.   emit = new Emit(io);
  118.   emit.BeginModule();        // need assembly module
  119.   emit.BeginClass();
  120.   }
  121.  
  122. void epilog()
  123.   {
  124.   emit.EndClass();
  125.   emit.EndModule();
  126.   }
  127.  
  128. void addInner(Var e)
  129.   {
  130.   /*
  131.    * validate this declaration as a potential variable
  132.    */
  133.   int id = e.getClassId();
  134. #if DEBUG
  135.   Console.WriteLine("addInner e=["+e+"]\n");
  136. #endif
  137.   if (id == Tok.T_EXTERN || id == Tok.T_STATIC)
  138.     io.Abort("Cannot allocate static within a method\n");
  139.   if (paramvar.FindByName(e.getName()) != null) /* cannot redefine param name */
  140.     io.Abort("Cannot redefine parameter name '" + e.getName() + "'\n");
  141.   if (localvar.FindByName(e.getName()) != null) /* check not already set */
  142.     io.Abort("Local variable '" + e.getName() + "' already defined\n");
  143.   localvar.add(e);
  144.   }
  145.  
  146. /*
  147.  * parse an inner declaration
  148.  */
  149. void declInner()
  150.   {
  151.   while (tok.IsDeclKeyword())
  152.     {
  153.     Var e = new Var();
  154. #if DEBUG
  155.     Console.WriteLine("declInner1 token=["+tok+"]\n");
  156. #endif
  157.  
  158.     CommentHolder();    /* mark comment position in insn stream */
  159.  
  160.     dataClass(e);        // parse the data class (static, auto, etc)
  161.     dataType(e);        // parse the type (int, unsigned, etc)
  162.     e.setName(tok.getValue()); // save the name in var
  163. #if DEBUG
  164.     Console.WriteLine("declInner2.0 token=["+tok+"]\n");
  165.     Console.WriteLine("declInner2.0 e=["+e+"]\n");
  166. #endif
  167.     addInner(e);            /* add this variable */
  168.     /*
  169.      * loop while there are additional variable names
  170.      */
  171.     while (io.getNextChar() == ',')
  172.       {
  173.       tok.scan();
  174.       if (tok.getFirstChar() != ',')
  175.     io.Abort("Expected ','");
  176.       tok.scan();
  177.       if (tok.getId() != Tok.T_IDENT)
  178.     io.Abort("Expected identifier");
  179.       e.setName(tok.getValue()); /* use value as the variable name */
  180. #if DEBUG
  181.       Console.WriteLine("declInner2.1 token=["+tok+"]\n");
  182.       Console.WriteLine("declInner2.1 e=["+e+"]\n");
  183. #endif
  184.       addInner(e);        /* reuse the class & type */
  185.       }
  186.     /*
  187.      * move beyond end of statement indicator
  188.      */
  189.     tok.scan();
  190.     if (tok.getFirstChar() != ';')
  191.     io.Abort("Expected ';'");
  192.     CommentFill();
  193.     tok.scan();        /* get token ready nor next parser step */
  194. #if DEBUG
  195.     Console.WriteLine("declInner3 token=["+tok+"]\n");
  196. #endif
  197.     }
  198.   }
  199.  
  200. void addOuter(Var e)
  201.   {
  202. #if DEBUG
  203.   Console.WriteLine("addOuter e=["+e+"]\n");
  204. #endif
  205.   /*
  206.    * validate this declaration as a potential variable
  207.    */
  208.   if (e.getClassId() == Tok.T_AUTO)
  209.     io.Abort("?Cannot allocate automatic variable outside a function\n");
  210.   if (staticvar.FindByName(e.getName()) != null)
  211.     io.Abort("?Cannot redefine static name '" + e.getName() + "'\n");
  212.   staticvar.add(e);
  213.   }
  214.  
  215. /*
  216.  * declOuter presumes that class & type have already been parsed
  217.  * this is done to distinguish between a function declaration and a
  218.  * variable declaration
  219.  */
  220. void declOuter(Var e)
  221.   {
  222. #if DEBUG
  223.   Console.WriteLine("declOuter1 token=["+tok+"]\n");
  224. #endif
  225.   e.setName(tok.getValue());    /* use value as the variable name */
  226.   addOuter(e);        /* add this variable */
  227.   emit.FieldDef(e);        /* issue the declaration */
  228.   if (e.getClassId() == Tok.T_DEFCLASS)
  229.     e.setClassId(Tok.T_STATIC);    /* make sure it knows its storage class */
  230.  
  231.   /*
  232.    * loop while there are additional variable names
  233.    */
  234.   while (io.getNextChar() == ',')
  235.     {
  236.     tok.scan();
  237.     if (tok.getFirstChar() != ',')
  238.     io.Abort("Expected ','");
  239.     tok.scan();
  240.     if (tok.getId() != Tok.T_IDENT)
  241.     io.Abort("Expected identifier");
  242.     e.setName(tok.getValue()); /* use value as the variable name */
  243.     addOuter(e);        /* add this variable */
  244.     emit.FieldDef(e);        /* issue the declaration */
  245.     if (e.getClassId() == Tok.T_DEFCLASS)
  246.       e.setClassId(Tok.T_STATIC);    /* make sure it knows its storage class */
  247.     }
  248.   /*
  249.    * move beyond end of statement indicator
  250.    */
  251.   tok.scan();
  252.   if (tok.getFirstChar() != ';')
  253.     io.Abort("Expected ';'");
  254.   CommentFill();
  255.   tok.scan();
  256. #if DEBUG
  257.   Console.WriteLine("declOuter2 token=["+tok+"]\n");
  258. #endif
  259.   }
  260.  
  261. void declFunc(Var e)
  262.   {
  263. #if DEBUG
  264.   Console.WriteLine("declFunc token=["+tok+"]\n");
  265. #endif
  266.   CommentHolder();    // start new comment
  267.   e.setName(tok.getValue()); /* value is the function name */
  268.   if (e.getName().Equals("main"))
  269.     {
  270.     if (Io.gendll)
  271.       io.Abort("Using main entrypoint when generating a DLL");
  272.     mainseen = true;
  273.     }
  274.   staticvar.add(e);        /* add function name to static VarList */
  275.   paramvar = paramList();    // track current param list
  276.   e.setParams(paramvar);    // and set it in func var
  277.   localvar = new VarList();    // track new local parameters
  278.   CommentFillPreTok();
  279.  
  280.   emit.FuncBegin(e);
  281.   if (tok.getFirstChar() != '{')
  282.     io.Abort("Expected '{'");
  283.   blockOuter(null, null);
  284.   emit.FuncEnd();
  285.   emit.IL();
  286.   if (Io.genlist)
  287.     emit.LIST();
  288.   emit.Finish();
  289.   }
  290.  
  291. /*
  292.  * parse the outerBlock seperately from inner block.
  293.  * specifically parse the declarations at the beginning of an outerblock
  294.  * the variable r tracks if the last statement was a return or not
  295.  */
  296. void blockOuter(String olabel, String ilabel)
  297.   {
  298.   bool r = false;
  299. #if DEBUG
  300.   Console.WriteLine("blockOuter1 token=["+tok+"]\n");
  301. #endif
  302.   CommentToken();    /* mark the position in insn stream */
  303.   tok.scan();
  304. #if DEBUG
  305.   Console.WriteLine("blockOuter2 token=["+tok+"]\n");
  306. #endif
  307.   declInner();
  308.   emit.LocalVars(localvar);
  309.  
  310.   while (tok.getFirstChar() != '}')
  311.     {
  312. #if DEBUG
  313.     Console.WriteLine("blockOuter3 token=["+tok+"]\n");
  314. #endif
  315.     if (io.EOF())
  316.       io.Abort("Expected statement, end of file encountered");
  317.     r = false;
  318.     switch (tok.getId())
  319.       {
  320.       case Tok.T_IF: fcIf(olabel, ilabel); continue; /* fcIf updates tok */
  321.       case Tok.T_WHILE: fcWhile(); break;
  322.       case Tok.T_FOR: fcFor(); break;
  323.       case Tok.T_BREAK: fcBreak(olabel); break;
  324.       case Tok.T_CONTINUE: fcContinue(ilabel); break;
  325.       case Tok.T_RETURN: fcReturn(); r = true; break;
  326.       default: statement(); break;
  327.       }
  328. #if DEBUG
  329.     Console.WriteLine("blockOuter4 token=["+tok+"]\n");
  330. #endif
  331.     }
  332.   if (!r)        /* if no outerscope return specified, try to default */
  333.     {
  334.     Var e = emit.GetFunc();    /* get function def */
  335.     if (e.getTypeId() != Tok.T_VOID)    /* make sure we can default to void */
  336.       {
  337.       if (!e.getName().Equals("main")) /* is it not main? */
  338.     io.Abort("No return value specified for non void function");
  339.       emit.LoadConst("0");    /* special case a dummy ret value */
  340.       }
  341.     emit.Ret();
  342.     }
  343.   CommentToken();        /* mark the position in insn stream */
  344.   tok.scan(); /* read beyond end of block */
  345. #if DEBUG
  346.   Console.WriteLine("blockOuter5 token=["+tok+"]\n");
  347. #endif
  348.   }
  349.  
  350. /* recognize and translate a statement block */
  351. void blockInner(String olabel, String ilabel)
  352.   {
  353. #if DEBUG
  354.   Console.WriteLine("blockInner1 token=["+tok+"]\n");
  355. #endif
  356.   if (tok.getFirstChar() == '{')    /* if begin, then get next token */
  357.     {
  358.     CommentToken();    /* mark the position in insn stream */
  359.     tok.scan();
  360. #if DEBUG
  361.     Console.WriteLine("blockInner2 token=["+tok+"]\n");
  362. #endif
  363.     if (tok.IsDeclKeyword())
  364.       io.Abort("Illegal inner declaration of variable");
  365.     while (tok.getFirstChar() != '}')
  366.       {
  367.       switch (tok.getId())
  368.     {
  369.     case Tok.T_IF: fcIf(olabel, ilabel); continue; /* fcIf updates tvp */
  370.     case Tok.T_WHILE: fcWhile(); break;
  371.     case Tok.T_FOR: fcFor(); break;
  372.     case Tok.T_BREAK: fcBreak(olabel); break;
  373.     case Tok.T_CONTINUE: fcContinue(ilabel); break;
  374.     case Tok.T_RETURN: fcReturn(); break;
  375.     default: statement(); break;
  376.     }
  377. #if DEBUG
  378.       Console.WriteLine("blockInner3 token=["+tok+"]\n");
  379. #endif
  380.       }
  381.     CommentToken(); /* mark the begin of source comment */
  382.     tok.scan(); /* read beyond end of blockInner */
  383.     }
  384.   else
  385.     {
  386.     switch (tok.getId())
  387.       {
  388.       case Tok.T_IF: fcIf(olabel, ilabel); break;
  389.       case Tok.T_WHILE: fcWhile(); break;
  390.       case Tok.T_FOR: fcFor(); break;
  391.       case Tok.T_BREAK: fcBreak(olabel); break;
  392.       case Tok.T_CONTINUE: fcContinue(ilabel); break;
  393.       case Tok.T_RETURN: fcReturn(); break;
  394.       default: statement(); break;
  395.       }
  396.     }
  397.   }
  398.  
  399. /*
  400.  * the flow of control routines
  401.  */
  402.  
  403. /* gen a unique label */
  404. String newLabel()
  405.   {
  406.   StringBuilder sb = new StringBuilder("L");
  407.   sb.Append(label_count++);
  408.   return (sb.ToString());
  409.   }
  410.  
  411. /*
  412.  * parse an if construct
  413.  * form is:
  414.    *    if (e) stmt-block else stmt-block
  415.    */
  416. void fcIf(String olabel, String ilabel)
  417.   {
  418.   String label1;
  419.   String label2;
  420.  
  421.   CommentHolder();    /* mark the position in insn stream */
  422.   tok.scan();
  423.   if (tok.getFirstChar() != '(')
  424.     io.Abort("Expected '('");
  425.  
  426.   boolExpr();
  427.   CommentFillPreTok();
  428.  
  429.   label1 = newLabel();
  430.   label2 = String.Copy(label1);
  431.  
  432.   emit.Branch("brfalse", label1);
  433.  
  434.   blockInner(olabel, ilabel); /* parse block or single statement */
  435.  
  436. #if DEBUG
  437.   Console.WriteLine("fcIf token=["+tok+"]\n");
  438. #endif
  439.   if (tok.getId() == Tok.T_ELSE)    /* sniff for else clause */
  440.     {
  441.     label2 = newLabel();
  442.     emit.Branch("br", label2);
  443.  
  444.     emit.Label(label1);
  445.     tok.scan();        /* get next token after else */
  446.     blockInner(olabel, ilabel); /* outer label, top of loop */
  447.     }
  448.   emit.Label(label2);
  449.   }
  450.  
  451.   /* parse and translate a while statement */
  452. void fcWhile()
  453.   {
  454.   String label1 = newLabel();
  455.   String label2 = newLabel();
  456.  
  457.   CommentHolder();    /* mark the position in insn stream */
  458.   emit.Label(label1);
  459.   tok.scan();
  460.   if (tok.getFirstChar() != '(')
  461.     io.Abort("Expected '('");
  462.  
  463.   boolExpr();
  464.   CommentFillPreTok();
  465.   emit.Branch("brfalse", label2);
  466.  
  467.   blockInner(label2, label1);    /* outer label, top of loop */
  468.   emit.Branch("br", label1);
  469.  
  470.   emit.Label(label2);
  471.   }
  472.  
  473. void fcFor()
  474.   {
  475.   String label1 = newLabel();
  476.   String label2 = newLabel();
  477.   String label3 = newLabel();
  478.   String label4 = newLabel();
  479.  
  480.   CommentHolder();    /* mark the position in insn stream */
  481.   tok.scan();
  482.   if (tok.getFirstChar() != '(')
  483.     io.Abort("Expected '('");
  484.  
  485.   /*
  486.    * the assignment statement
  487.    */
  488.   tok.scan();            /* i=0 */
  489.   if (tok.getFirstChar() == ';')    /* allow null assignment */
  490.     {
  491.     CommentFill();
  492.     tok.scan();        /* move beyond null statement */
  493.     }
  494.   else
  495.     {
  496.     statement();        /* parse the statement */
  497.                   /* statement also closes the comment */
  498.     }
  499.  
  500.   /*
  501.    * the logical test
  502.    */
  503.   emit.Label(label1);
  504.   CommentHolder();            /* mark the position in insn stream */
  505.  
  506.   if (tok.getFirstChar() == ';')    /* allow null test */
  507.     {
  508.     CommentFill("<no test>");
  509.     tok.scan();        /* move past the semi */
  510.     }
  511.   else
  512.     {
  513.     boolExpr();        /* i<max */
  514.     if (tok.getFirstChar() != ';')
  515.       io.Abort("Expected ';'");
  516.     CommentFill();
  517.     tok.scan();
  518.     emit.Branch("brfalse", label4); /* test for result */
  519.     }
  520.   emit.Branch("br", label3);    /* emit. branch to statement block */
  521.  
  522.   /*
  523.    * the increment statement
  524.    */
  525.   CommentHolder();            /* mark comment position in insn stream */
  526.  
  527.   emit.Label(label2);
  528.   if (tok.getFirstChar() == ')')    /* allow null increment statement */
  529.     {
  530.     CommentFill();        /* end comment here */
  531.     tok.scan();            /* move to next token */
  532.     }
  533.   else
  534.     {
  535.     /*
  536.      * this is similar to assign, but ends with ')'
  537.      */
  538.     String varname = tok.getValue();
  539.     tok.scan();
  540.     if (tok.getFirstChar() != '=')
  541.       io.Abort("Expected '='");
  542.     tok.scan();
  543.     boolExpr();
  544.     emit.Store(lookup_name(varname));
  545.     if (tok.getFirstChar() != ')')
  546.       io.Abort("Expected ')'");
  547.     CommentFill();        /* end comment here */
  548.     tok.scan();            /* move to next token */
  549.     }
  550.   emit.Branch("br", label1);
  551.  
  552.   /*
  553.    * the statement block
  554.    */
  555.   emit.Label(label3);
  556.   blockInner(label4, label2);    /* outer label, top of loop */
  557.   emit.Branch("br", label2);    /* go to 3rd term (usually incr) */
  558.  
  559.   emit.Label(label4);
  560.   }
  561.  
  562. /* recognize and translate a break */
  563. void fcBreak(String olabel)
  564.   {
  565.   CommentHolder();    /* mark the position in insn stream */
  566.   if (olabel != null)
  567.     emit.Branch("br", olabel);
  568.   else
  569.     io.Abort("No loop to break from");
  570.   tok.scan();
  571.   if (tok.getFirstChar() != ';')
  572.     io.Abort("Expected ';'");
  573.   CommentFill();
  574.   tok.scan();
  575.   }
  576.  
  577. /* parse a continue */
  578. void fcContinue(String ilabel)
  579.   {
  580.   CommentHolder();    /* mark the position in insn stream */
  581.   if (ilabel != null)
  582.     emit.Branch("br", ilabel);
  583.   else
  584.     io.Abort("No loop to break from");
  585.   tok.scan();
  586.   if (tok.getFirstChar() != ';')
  587.     io.Abort("Expected ';'");
  588.   CommentFill();
  589.   tok.scan();
  590.   }
  591.  
  592. /* parse a return */
  593. void fcReturn()
  594.   {
  595.   Var e = emit.GetFunc();
  596.   CommentHolder();    /* mark the position in insn stream */
  597.   tok.scan();        /* get the return value */
  598.   if (tok.getFirstChar() == ';')    /* if end of statment */
  599.     {
  600.     if (e.getTypeId() != Tok.T_VOID)
  601.       io.Abort("Expected value for return type");
  602.     }
  603.   else
  604.     {
  605.     if (e.getTypeId() == Tok.T_VOID)
  606.       io.Abort("Unexpected value for void return type");
  607.     boolExpr();        /* parse as expression */
  608.     }
  609.   emit.Ret();            /* issue the return (value is on stack) */
  610.   CommentFill();
  611.   tok.scan();            /* move past the semi */
  612.   }
  613.  
  614. /*
  615.  * expression logic
  616.  */
  617.  
  618. void ident()
  619.   {
  620. #if DEBUG
  621.   Console.WriteLine("ident token=["+tok+"]\n");
  622. #endif
  623.   if (io.getNextChar() == '(')    /* this must be a function call */
  624.     {
  625.     String vname = tok.getValue();
  626.     Var e;
  627.     tok.scan();        /* eat the left paren */
  628.     tok.scan();        /* get the first parameter (or none) */
  629.     if (tok.getFirstChar() != ')')    /* if there are params */
  630.       {
  631.       boolExpr();        /* parse first param */
  632.       while (tok.getFirstChar() == ',') /* while there are more params */
  633.     {
  634.     tok.scan();        /* get the next token */
  635.     boolExpr();        /* parse now as an expression */
  636.     }
  637.       if (tok.getFirstChar() != ')')    /* must find closing paren */
  638.     io.Abort("Expected ')'");
  639.       tok.scan();        /* move to next token */
  640.       }
  641.     e = staticvar.FindByName(vname); /* find the symbol */
  642.     if (e.getTypeId() == Tok.T_VOID)    /* if function value is void */
  643.       io.Abort("Using void function where expecting a value");
  644.     emit.Call(e);        /* construct the call */
  645.     }
  646.   else
  647.     {
  648.     emit.Load(lookup_name(tok.getValue())); /* load this symbol */
  649.     tok.scan();        /* get the next token */
  650.     }
  651.   }
  652.  
  653. void factor()
  654.   {
  655. #if DEBUG
  656.   Console.WriteLine("factor token=["+tok+"]\n");
  657. #endif
  658.   if (tok.getFirstChar() == '(')
  659.     {
  660.     tok.scan();            /* get next token */
  661.     boolExpr();
  662.     if (tok.getFirstChar() != ')')
  663.       io.Abort("Expected ')'");
  664.     tok.scan();            /* get next token */
  665.     }
  666.   else if (tok.getId() == Tok.T_IDENT)
  667.     {
  668.     ident();
  669.     }
  670.   else
  671.     {
  672.     emit.LoadConst(tok.getValue());
  673.     tok.scan();            /* get next token */
  674.     }
  675.   }
  676.  
  677. void unaryFactor()
  678.   {
  679.   if (tok.getId() == Tok.T_ADD_OP) /* unary plus */
  680.     {
  681.     tok.scan();        /* get the next token */
  682.     factor();            /* process the factor */
  683.     return;
  684.     }
  685.   if (tok.getId() == Tok.T_SUB_OP) /* unary minus */
  686.     {
  687.     tok.scan();
  688.     if (tok.getId() == Tok.T_DIGITS)
  689.       {
  690.       StringBuilder sb = new StringBuilder("-"); /* recreate the String */
  691.       sb.Append(tok.getValue());
  692.       emit.LoadConst(sb.ToString());    /* emit. load const for String */
  693.       tok.scan();
  694.       return;
  695.       }
  696.     factor();            /* process the factor */
  697.     emit.Insn("neg");
  698.     return;
  699.     }
  700.   factor();            /* no unary, so pass this token down */
  701.   }
  702.  
  703. void termMult()
  704.   {
  705.   tok.scan();
  706.   factor();
  707.   emit.Insn("mul");
  708.   }
  709.  
  710. void termDiv()
  711.   {
  712.   tok.scan();
  713.   factor();
  714.   emit.Insn("div");
  715.   }
  716.  
  717. /* completion of term processing (called by term and firstTerm) */
  718. void term1()
  719.   {
  720.   while (tok.getId() == Tok.T_MUL_OP || tok.getId() == Tok.T_DIV_OP)
  721.     {
  722.     switch (tok.getId())
  723.       {
  724.       case Tok.T_MUL_OP: termMult(); break;
  725.       case Tok.T_DIV_OP: termDiv(); break;
  726.       }
  727.     }
  728.   }
  729.  
  730. /* parse and translate math term */
  731. void term()
  732.   {
  733.   factor();
  734.   term1();
  735.   }
  736.  
  737. /* check term with possible leading sign */
  738. void firstTerm()
  739.   {
  740.   unaryFactor();
  741.   term1();
  742.   }
  743.  
  744. /* translate an add */
  745. void exprAdd()
  746.   {
  747.   tok.scan();
  748.   term();
  749.   emit.Insn("add");
  750.   }
  751.  
  752. /* translate a subtract */
  753. void exprSub()
  754.   {
  755.   tok.scan();
  756.   term();
  757.   emit.Insn("sub");
  758.   }
  759.  
  760. /* parse an expression */
  761. void mathExpr()
  762.   {
  763. #if DEBUG
  764.   Console.WriteLine("mathExpr1 token=["+tok+"]\n");
  765. #endif
  766.   firstTerm();
  767. #if DEBUG
  768.   Console.WriteLine("mathExpr2 token=["+tok+"]\n");
  769. #endif
  770.   while (tok.getId() == Tok.T_ADD_OP || tok.getId() == Tok.T_SUB_OP)
  771.     {
  772.     switch (tok.getId())
  773.       {
  774.       case Tok.T_ADD_OP: exprAdd(); break;
  775.       case Tok.T_SUB_OP: exprSub(); break;
  776.       }
  777.     }
  778.   }
  779.  
  780. /* recognize and translate a relational "equal" */
  781. void relEQ()
  782.   {
  783.   tok.scan();
  784.   mathExpr();
  785.   emit.Insn("ceq");
  786.   }
  787.  
  788. /* recognize and translate a relational "not equal" */
  789. void relNEQ()
  790.   {
  791.   tok.scan();
  792.   mathExpr();
  793.   emit.Insn("ceq");
  794.   emit.LoadConst("1");
  795.   emit.Insn("ceq");
  796.   }
  797.  
  798. /* recognize and translate a relational "less than" */
  799. void relLTR()
  800.   {
  801.   tok.scan();
  802.   mathExpr();
  803.   emit.Insn("clt");
  804.   }
  805.  
  806. /* recognize and translate a relational "greater than" */
  807. void relGTR()
  808.   {
  809.   tok.scan();
  810.   mathExpr();
  811.   emit.Insn("cgt");
  812.   }
  813.  
  814. void relGEQ()
  815.   {
  816.   tok.scan();
  817.   mathExpr();
  818.   emit.Insn("clt");
  819.   emit.LoadConst("0");
  820.   emit.Insn("ceq");
  821.   }
  822.  
  823. void relLEQ()
  824.   {
  825.   tok.scan();
  826.   mathExpr();
  827.   emit.Insn("cgt");
  828.   emit.LoadConst("0");
  829.   emit.Insn("ceq");
  830.   }
  831.  
  832. /* parse a relation */
  833. void relExpr()
  834.   {
  835.   mathExpr();
  836. #if DEBUG
  837.   Console.WriteLine("relExpr token=["+tok+"]\n");
  838. #endif
  839.   switch (tok.getId())
  840.     {
  841.     case Tok.T_EQ_OP: relEQ(); break;
  842.     case Tok.T_NEQ_OP: relNEQ(); break;
  843.     case Tok.T_LT_OP: relLTR(); break;
  844.     case Tok.T_GT_OP: relGTR(); break;
  845.     case Tok.T_GE_OP: relGEQ(); break;
  846.     case Tok.T_LE_OP: relLEQ(); break;
  847.     }
  848.   }
  849.  
  850. /* parse factor with NOT */
  851. void notFactor()
  852.   {
  853. #if DEBUG
  854.   Console.WriteLine("notFactor token=["+tok+"]\n");
  855. #endif
  856.   if (tok.getId() == Tok.T_NOT_OP)
  857.     {
  858.     relExpr();
  859.     emit.Insn("not");
  860.     }
  861.   else
  862.     relExpr();
  863.   }
  864.  
  865. /* recognize and translate a boolean OR */
  866. void boolOr()
  867.   {
  868.   tok.scan();
  869.   termBool();
  870.   emit.Insn("or");
  871.   }
  872.  
  873. /* recognize and transate an exclusize or (XOR) */
  874. void boolXor()
  875.   {
  876.   tok.scan();
  877.   termBool();
  878.   emit.Insn("xor");
  879.   }
  880.  
  881. /* recognize and transate a bitwise AND */
  882. void boolAnd()
  883.   {
  884.   tok.scan();
  885.   termBool();
  886.   emit.Insn("and");
  887.   }
  888.  
  889. /* parse an translate a boolean term */
  890. void termBool()
  891.   {
  892.   notFactor();
  893.   while (tok.getId() == Tok.T_OR_OP
  894.      || tok.getId() == Tok.T_XOR_OP
  895.      || tok.getId() == Tok.T_AND_OP)
  896.     {
  897.     switch (tok.getId())
  898.       {
  899.       case Tok.T_OR_OP: boolOr(); break;
  900.       case Tok.T_XOR_OP: boolXor(); break;
  901.       case Tok.T_AND_OP: boolAnd(); break;
  902.       }
  903. #if DEBUG
  904.     Console.WriteLine("termBool token=["+tok+"]\n");
  905. #endif
  906.     }
  907.   }
  908.  
  909. /* parse and translate a boolean expression */
  910. void boolExpr()
  911.   {
  912.   termBool();
  913.   int id = tok.getId();
  914.   if (id == Tok.T_LOG_OR_OP || id == Tok.T_LOG_AND_OP)
  915.     {
  916.     String label1 = newLabel();
  917.     String label2 = newLabel();
  918.     String label3 = newLabel();
  919.     while (true)
  920.       {
  921.       id = tok.getId();
  922.       if (id == Tok.T_LOG_AND_OP)
  923.     emit.Branch("brfalse", label1);    // optimize the logical and
  924.       else if (id == Tok.T_LOG_OR_OP)
  925.     emit.Branch("brtrue", label2); // optimize the logical or
  926.       else
  927.     break;
  928.       tok.scan();
  929.       termBool();
  930.       }
  931.     emit.Branch("brtrue", label2);
  932.     emit.Label(label1);    // false path
  933.     emit.LoadConst("0");
  934.     emit.Branch("br",label3);
  935.     emit.Label(label2);    // true path
  936.     emit.LoadConst("1");
  937.     emit.Label(label3);    // common path
  938.     }
  939.   }
  940.  
  941. Var lookup_name(String s)
  942.   {
  943.   Var e;
  944.   if ((e = localvar.FindByName(s)) == null)
  945.     if ((e = paramvar.FindByName(s)) == null)
  946.       if ((e = staticvar.FindByName(s)) == null)
  947.     {
  948.     io.Abort("Undefined variable '"+ s + "'\n");
  949.     }
  950.   return e;
  951.   }
  952.  
  953. /*
  954.  * parse a generic statement
  955.  *
  956.  * possible forms are:
  957.  * lvalue = <expr> ;
  958.  * function() ;
  959.  * and <expr> can contain: function or arithmetic expressions
  960.  * 
  961.  * so for a recursive descent parser we need to test for a possible
  962.  * '=' or '('
  963.  */
  964. void statement()
  965.   {
  966.   Var e;
  967.   String vname = tok.getValue();
  968.  
  969.   CommentHolder();    /* mark the position in insn stream */
  970.   switch (io.getNextChar())
  971.     {
  972.     case '(':            /* this is a function call */
  973.       tok.scan();
  974.       if (tok.getFirstChar() != '(')
  975.     io.Abort("Expected '('");
  976.       tok.scan();        /* get the first parameter (or none) */
  977.       if (tok.getFirstChar() != ')')    /* if there are params */
  978.     {
  979.     boolExpr();        /* parse first param */
  980.     while (tok.getFirstChar() == ',') /* while there are more params */
  981.       {
  982.       tok.scan();        /* get the next token */
  983.       boolExpr();        /* parse now as an expression */
  984.       }
  985.     if (tok.getFirstChar() != ')') /* must find closing paren */
  986.       io.Abort("Expected ')'");
  987.     }
  988.       CommentFill();
  989.       tok.scan();        /* move to next token */
  990.       e = staticvar.FindByName(vname); /* find the symbol (e cannot be null) */
  991.       emit.Call(e);
  992.       if (e.getTypeId() != Tok.T_VOID) /* if function value not void */
  993.     emit.Insn("pop");    /* then pop the unused return value */
  994.       break;
  995.     case '=':            /* if we have equal, then parse assign */
  996.       tok.scan();
  997.       if (tok.getFirstChar() != '=')
  998.     io.Abort("Expected '='");
  999.       tok.scan();
  1000.       boolExpr();
  1001.       CommentFill();
  1002.       emit.Store(lookup_name(vname));
  1003.       break;
  1004.     default:
  1005.       {
  1006.       StringBuilder sb = new StringBuilder();
  1007.       sb.Append("Unexpected character '");
  1008.       sb.Append(io.getNextChar());
  1009.       sb.Append("'\n");
  1010.       io.Abort(sb.ToString());
  1011.       return;
  1012.       }
  1013.     }
  1014.   if (tok.getFirstChar() != ';')
  1015.     io.Abort("Expected ';'");
  1016.   tok.scan();
  1017.   }
  1018.  
  1019. public Parse(Io i, Tok t)
  1020.   {
  1021.   io = i;
  1022.   tok = t;
  1023.   staticvar = new VarList();    // init the static variables list
  1024.   }
  1025.  
  1026. /* parse and translate a program */
  1027. public void program()
  1028.   {
  1029.   prolog();
  1030.   while (tok.NotEOF())
  1031.     {
  1032.     outerDecl();
  1033.     }
  1034.   if (Io.genexe && !mainseen)
  1035.     io.Abort("Generating executable with no main entrypoint");
  1036.   epilog();
  1037.   }
  1038.  
  1039. void CommentToken()
  1040.   {
  1041.   io.commentBegin(tok.getValue());    /* mark the begin of source comment */
  1042.   emit.CommentHolder();
  1043.   emit.CommentFill(io.commentEndTok(tok.getValue())); /* copy and emit comment */
  1044.   }
  1045.  
  1046. void CommentHolder()
  1047.   {
  1048.   io.commentBegin(tok.getValue());    /* mark the begin of source comment */
  1049.   emit.CommentHolder();
  1050.   }
  1051.  
  1052. void CommentFill()
  1053.   {
  1054.   emit.CommentFill(io.commentEndTok(tok.getValue())); /* copy and emit comment */
  1055.   }
  1056.  
  1057. void CommentFill(String s)
  1058.   {
  1059.   emit.CommentFill(io.commentEndTok(tok.getValue()) + s);        /* end the comment (no test) */
  1060.   }
  1061.  
  1062. void CommentFillPreTok()
  1063.   {
  1064.   emit.CommentFill(io.commentEndPreTok(tok.getValue())); /* copy and emit source */
  1065.   }
  1066. }
  1067.  
  1068. }
  1069.