Mega Code Archive

 
Categories / C# / Development Class
 

This module contains the recursive descent parser that does not use variables

/* C#: The Complete Reference  by Herbert Schildt  Publisher: Osborne/McGraw-Hill (March 8, 2002) ISBN: 0072134852 */ /*      This module contains the recursive descent     parser that does not use variables.  */    using System;    // Exception class for parser errors.  class ParserException : ApplicationException {    public ParserException(string str) : base(str) { }       public override string ToString() {      return Message;    }  }    class Parser {    // Enumerate token types.    enum Types { NONE, DELIMITER, VARIABLE, NUMBER };    // Enumerate error types.    enum Errors { SYNTAX, UNBALPARENS, NOEXP, DIVBYZERO };      string exp;    // refers to expression string    int expIdx;    // current index into the expression    string token;  // holds current token    Types tokType; // holds token's type      // Parser entry point.    public double Evaluate(string expstr)    {      double result;          exp = expstr;      expIdx = 0;          try {         GetToken();        if(token == "") {          SyntaxErr(Errors.NOEXP); // no expression present          return 0.0;        }          EvalExp2(out result);          if(token != "") // last token must be null          SyntaxErr(Errors.SYNTAX);          return result;      } catch (ParserException exc) {        // Add other error handling here, as desired.        Console.WriteLine(exc);        return 0.0;      }    }        // Add or subtract two terms.    void EvalExp2(out double result)    {      string op;      double partialResult;          EvalExp3(out result);      while((op = token) == "+" || op == "-") {        GetToken();        EvalExp3(out partialResult);        switch(op) {          case "-":            result = result - partialResult;            break;          case "+":            result = result + partialResult;            break;        }      }    }        // Multiply or divide two factors.    void EvalExp3(out double result)    {      string op;      double partialResult = 0.0;          EvalExp4(out result);      while((op = token) == "*" ||             op == "/" || op == "%") {        GetToken();        EvalExp4(out partialResult);        switch(op) {          case "*":            result = result * partialResult;            break;          case "/":            if(partialResult == 0.0)              SyntaxErr(Errors.DIVBYZERO);            result = result / partialResult;            break;          case "%":            if(partialResult == 0.0)              SyntaxErr(Errors.DIVBYZERO);            result = (int) result % (int) partialResult;            break;        }      }    }        // Process an exponent.    void EvalExp4(out double result)    {      double partialResult, ex;      int t;          EvalExp5(out result);      if(token == "^") {        GetToken();        EvalExp4(out partialResult);        ex = result;        if(partialResult == 0.0) {          result = 1.0;          return;        }        for(t=(int)partialResult-1; t > 0; t--)          result = result * (double)ex;      }    }        // Evaluate a unary + or -.    void EvalExp5(out double result)    {      string  op;          op = "";      if((tokType == Types.DELIMITER) &&          token == "+" || token == "-") {        op = token;        GetToken();      }      EvalExp6(out result);      if(op == "-") result = -result;    }        // Process a parenthesized expression.    void EvalExp6(out double result)    {      if((token == "(")) {        GetToken();        EvalExp2(out result);        if(token != ")")          SyntaxErr(Errors.UNBALPARENS);        GetToken();      }      else Atom(out result);    }        // Get the value of a number.    void Atom(out double result)    {      switch(tokType) {        case Types.NUMBER:          try {            result = Double.Parse(token);          } catch (FormatException) {            result = 0.0;            SyntaxErr(Errors.SYNTAX);          }          GetToken();          return;        default:          result = 0.0;          SyntaxErr(Errors.SYNTAX);          break;      }    }        // Handle a syntax error.    void SyntaxErr(Errors error)    {      string[] err = {        "Syntax Error",        "Unbalanced Parentheses",        "No Expression Present",        "Division by Zero"      };        throw new ParserException(err[(int)error]);    }        // Obtain the next token.    void GetToken()    {      tokType = Types.NONE;      token = "";           if(expIdx == exp.Length) return; // at end of expression          // skip over white space      while(expIdx < exp.Length &&            Char.IsWhiteSpace(exp[expIdx])) ++expIdx;        // trailing whitespace ends expression      if(expIdx == exp.Length) return;        if(IsDelim(exp[expIdx])) { // is operator        token += exp[expIdx];        expIdx++;        tokType = Types.DELIMITER;      }      else if(Char.IsLetter(exp[expIdx])) { // is variable        while(!IsDelim(exp[expIdx])) {          token += exp[expIdx];          expIdx++;          if(expIdx >= exp.Length) break;        }        tokType = Types.VARIABLE;      }      else if(Char.IsDigit(exp[expIdx])) { // is number        while(!IsDelim(exp[expIdx])) {          token += exp[expIdx];          expIdx++;          if(expIdx >= exp.Length) break;        }        tokType = Types.NUMBER;      }    }        // Return true if c is a delimiter.    bool IsDelim(char c)    {      if((" +-/*%^=()".IndexOf(c) != -1))        return true;      return false;    }      }  // Demonstrate the parser.    public class ParserDemo {    public static void Main()    {      string expr;      Parser p = new Parser();        Console.WriteLine("Enter an empty expression to stop.");        for(;;) {        Console.Write("Enter expression: ");        expr = Console.ReadLine();        if(expr == "") break;        Console.WriteLine("Result: " + p.Evaluate(expr));      }    }  }