Páginas

martes, 14 de febrero de 2012

Getting an expression evaluated

Have you ever try to make a parser without any parsing technique? I had to. My first year in university we were oriented to make a Functions Evaluator, that allows the user to evaluate expressions, but also graph, derivate and compose Functions. Was quite a challenge.

While the Functions hierarchy, wich I pretend to post some time in the near future, was nicely done based on the Math namespace, the parse part wasn´t. I ended up with a cs file of more than 640 lines of code and a lot of recursive work. That kept me very upset, because even when the job was done and it ran (still does) very well is not a code I´m proud of.

But I got a major revelation when a couple of years later in the Compiler course we were introduced to Context-Sensitive Grammars and ANTLR and the example was an expression grammar. First thing I did was running ANTLR and get revenge in a couple of minutes of all the sleepless nights in first year. This is the basics operations version (+-*/), but the remaining functions are easily addable.


options
{
 language = 'CSharp';
}
expression returns [int value]
 : t = term {$value = $t.value;}
 ('+' t = term {$value += $t.value;}
 | '-' t = term {$value -= $t.value;}) *;

term  returns [int value]
 :  f = factor {$value = $f.value;}
 ('*'  f = factor {$value *= $f.value;}
 | '/' f = factor {if($f.value != 0)
    $value /= $f.value;
      else
       Console.WriteLine("Not Divide by Zero");})*; 
factor  returns [int value]
 : NUMBER {$value = int.Parse($NUMBER.text);}
 | '('e = expression')'{$value = $e.value;};

NUMBER 
 : (DIGIT)+;
fragment DIGIT
 : '0'..'9';

After the lexer and parser code generation through the ANTLR option, the rest was only add the Antlr.Runtime.dll reference to the project and code what follows:

  static void Main(string[] args)
        {            
            string exp = Console.ReadLine();

            ANTLRStringStream stream = new ANTLRStringStream(exp);
            calcLexer lexer = new calcLexer(stream);
            CommonTokenStream tokenStream = new CommonTokenStream(lexer);
            calcParser parser = new calcParser(tokenStream);
            
            Console.WriteLine(parser.expression());
                       
        }

No hay comentarios:

Publicar un comentario