{"id":12,"date":"2008-07-27T15:46:23","date_gmt":"2008-07-27T13:46:23","guid":{"rendered":"http:\/\/floris.briolas.nl\/floris\/?p=12"},"modified":"2011-10-11T08:16:36","modified_gmt":"2011-10-11T07:16:36","slug":"simple-calculator-with-antlr","status":"publish","type":"post","link":"https:\/\/floris.briolas.nl\/floris\/2008\/07\/simple-calculator-with-antlr\/","title":{"rendered":"Simple Calculator with Antlr."},"content":{"rendered":"<p>For quite some time I&#8217;ve been interested in creating scripting languages to make existing applications more flexible than thought possible. After writing a couple of parsers I&#8217;ve stumbled upon <a href=\"http:\/\/www.antlr.org\">ANTLR<\/a> (ANother Tool for Language Recognition) which is a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Lexical_analysis\">Lexer<\/a> and <a href=\"http:\/\/en.wikipedia.org\/wiki\/Parsing\">Parser<\/a> all in one.<\/p>\n<p>Although I&#8217;m aware of the existence of a couple of other tools, such as &#8220;yacc, lex,gold parser,.. &#8221; this is the first tool I&#8217;m going to try out. I see a appliance to read <a href=\"http:\/\/en.wikipedia.org\/wiki\/Scalable_Vector_Graphics\">svg<\/a> files, and generate code (c#\/Java\/vb\/ada) that will draw the figure.<\/p>\n<p>Here is a preview of what this sample aims to:<\/p>\n<p><object width=\"668\" height=\"336\" classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" codebase=\"http:\/\/download.macromedia.com\/pub\/shockwave\/cabs\/flash\/swflash.cab#version=6,0,40,0\"><param name=\"src\" value=\"\/floris\/wp-content\/uploads\/2008\/07\/simplecalc1.swf\" \/><\/object><br \/>\nBut first things first, I longed to create a simple calculator, helping me to asses the possibilities of ANTLR, with a little help from :<a href=\"http:\/\/www.amazon.com\/gp\/offer-listing\/0978739256?ie=UTF8&amp;tag=acodernamedfl-20&amp;linkCode=am2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0978739256\">The Definitive ANTLR Reference: Building Domain-Specific Languages (Pragmatic Programmers)<\/a><img decoding=\"async\" loading=\"lazy\" style=\"border: none !important; margin: 0px !important;\" src=\"http:\/\/www.assoc-amazon.com\/e\/ir?t=acodernamedfl-20&amp;l=am2&amp;o=1&amp;a=0978739256\" alt=\"\" width=\"1\" height=\"1\" border=\"0\" \/> (Rather helpfull), I&#8217;ve managed the job quite well.<\/p>\n<p>Since I&#8217;ve seen some questions on the Internet requesting a simple example for a simple calculator grammar, here it is:<\/p>\n<pre class=\"antlr\">grammar SimpleCalc;\r\n\r\ntokens {\r\nPLUS \t= '+' ;\r\nMINUS\t= '-' ;\r\nMULT\t= '*' ;\r\nDIV\t= '\/' ;\r\nRPAREN\t= ')' ;\r\nLPAREN\t= '(' ;\r\nASSIGN\t= '=' ;\r\n}\r\n\r\n\/*----------------\r\n* PARSER RULES\r\n*----------------*\/\r\n\r\nprog :\t\tstat+;\r\nstat :\t\texpr NEWLINE\r\n\t|\tID ASSIGN expr NEWLINE\r\n\t|\tNEWLINE; \t\t\t\/\/Do nothing\r\n\r\nexpr \t:\tmultExpr ((PLUS | MINUS )multExpr)*;\r\n\r\nmultExpr:\tatom ((MULT | DIV) atom )*;\r\n\r\natom \t:\tINT\r\n\t|\tID\r\n\t|\tLPAREN expr RPAREN;\r\n\r\n\/*----------------\r\n* LEXER RULES\r\n*----------------*\/\r\n\r\nID \t:\t('a'..'z'|'A'..'Z')+;\r\nINT \t:\t'0'..'9'+;\r\nNEWLINE :\t'\\r'?'\\n';\r\nWS \t:\t(' '|'\\t'|'\\n'|'\\r')+;<\/pre>\n<p>The grammar above can handle expressions such as:<\/p>\n<blockquote><p>1+2*3<br \/>\na=4-5<br \/>\nc=a*(6\/2)<\/p><\/blockquote>\n<p>Now one has to add actions to the rules these will look like:<\/p>\n<p><code><strong>atom <\/strong>returns[int value] <strong>&lt;==Tell Antlr this rule is implemented as a function, returning an int.<\/strong><br \/>\n: INT {$value = int.Parse($INT.text);} <strong>&lt;==The return value '$value' is assign the parsed as an integer string value of int.<\/strong><br \/>\n<\/code><\/p>\n<p>Now all you need to do is fill every thing in. When an ID follow by an assignment (a=6) is encounter it will be placed in a Dictionary.<\/p>\n<p>After adding the appropriate actions the calculator is finished, it works internally with an int, so all divisions are integer divisions!. Adaptation for doubles will be no problem at all, but is left to you.<\/p>\n<pre class=\"antlr\">grammar SimpleCalc3;\r\n\r\noptions\r\n{\r\nlanguage=CSharp;\r\n}\r\n\r\ntokens {\r\nPLUS \t= '+' ;\r\nMINUS\t= '-' ;\r\nMULT\t= '*' ;\r\nDIV\t= '\/' ;\r\nRPAREN\t= ')' ;\r\nLPAREN\t= '(' ;\r\nASSIGN\t= '=' ;\r\n}\r\n\r\n@members\r\n{\r\npublic static System.Collections.Generic.Dictionary IDTable = new System.Collections.Generic.Dictionary();\r\n\r\npublic static void Main(string[] args)\r\n{\r\n  Console.WriteLine(\"type '@' to quit...\");\r\n  string line = \"\";\r\n  while (true)\r\n  {\r\n      line = Console.ReadLine();\r\n      if (line.Contains(\"@\"))\r\n        break;\r\n\r\n      SimpleCalc3Lexer lex = new SimpleCalc3Lexer(new ANTLRStringStream(line+Environment.NewLine));\r\n      CommonTokenStream tokens = new CommonTokenStream(lex);\r\n      SimpleCalc3Parser parser = new SimpleCalc3Parser(tokens);\r\n\r\n      try\r\n      {\r\n        parser.prog();\r\n      }\r\n      catch (RecognitionException e)\r\n      {\r\n        Console.Error.WriteLine(e.StackTrace);\r\n      }\r\n  }\r\n}\r\n\r\n}\r\n\r\n\/*----------------\r\n* PARSER RULES\r\n*----------------*\/\r\n\r\nprog :\tstat+;\r\nstat :\texpr NEWLINE\t\t\t{System.Console.WriteLine($expr.value);}\r\n|\tID ASSIGN expr NEWLINE\t\t{IDTable[$ID.Text] =$expr.value;}\r\n|\tNEWLINE; \t\t\t\/\/Do nothing\r\n\r\nexpr returns[int value]\r\n:\ta=multExpr {$value = $a.value;} (\r\nPLUS b=multExpr {$value+=$b.value;}\r\n|\r\nMINUS b=multExpr{$value-=$b.value;})*;\r\n\r\nmultExpr returns[int value]\r\n:\ta=atom {$value = $a.value;} (\r\nMULT b=atom {$value*=$b.value;}\r\n|\r\nDIV b=atom{$value\/=$b.value;})*;\r\n\r\natom returns[int value]\r\n:\tINT\t\t\t\t{$value = int.Parse($INT.text);}\r\n|\tID\t\t\t\t{if (IDTable.ContainsKey($ID.Text)){$value = IDTable[$ID.Text];}else{System.Console.WriteLine(\"ID does not exist\");}}\r\n|\tLPAREN expr RPAREN\t\t{$value = $expr.value;};\r\n\r\n\/*----------------\r\n* LEXER RULES\r\n*----------------*\/\r\n\r\nID :\t('a'..'z'|'A'..'Z')+;\r\n\r\nINT :\t'0'..'9'+;\r\n\r\nNEWLINE :\t'\\r'?'\\n';\r\n\r\nWS :\t(' '|'\\t'|'\\n'|'\\r')+ {Skip();};<\/pre>\n<p>If you desire a working example, please download <a href=\"http:\/\/floris.briolas.nl\/floris\/downloads\/simplecalc.rar\">this file<\/a>, Included are the .net binaries (.dll) from the antlr&#8217;s website. When your enviroment path is set correctly to the c# compiler, you will be able to run make.cmd to create the console application.<br \/>\nIf you want to download the ANTLR binaries yourself, get them at <a href=\"http:\/\/www.antlr.org\/download.html\">the original site<\/a>, look for &#8220;ANTLR Tool Binaries&#8221;.<\/p>\n<p>enjoy!<\/p>\n<p>*Update 24-aug-2008: Added the grammars to the zip.<br \/>\n*Update 27-apr-2009: Added sample movie.<br \/>\n*Update 13-oct-2009: Syntax Highlighting<\/p>\n<p><strong>Please, if you have questions or comments, let us know.<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>For quite some time I&#8217;ve been interested in creating scripting languages to make existing applications more flexible than thought possible. After writing a couple of parsers I&#8217;ve stumbled upon ANTLR (ANother Tool for Language Recognition) which is a Lexer and Parser all in one. Although I&#8217;m aware of the existence of a couple of other [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_newsletter_tier_id":0,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[3],"tags":[6,7],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p61yPs-c","_links":{"self":[{"href":"https:\/\/floris.briolas.nl\/floris\/wp-json\/wp\/v2\/posts\/12"}],"collection":[{"href":"https:\/\/floris.briolas.nl\/floris\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/floris.briolas.nl\/floris\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/floris.briolas.nl\/floris\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/floris.briolas.nl\/floris\/wp-json\/wp\/v2\/comments?post=12"}],"version-history":[{"count":19,"href":"https:\/\/floris.briolas.nl\/floris\/wp-json\/wp\/v2\/posts\/12\/revisions"}],"predecessor-version":[{"id":360,"href":"https:\/\/floris.briolas.nl\/floris\/wp-json\/wp\/v2\/posts\/12\/revisions\/360"}],"wp:attachment":[{"href":"https:\/\/floris.briolas.nl\/floris\/wp-json\/wp\/v2\/media?parent=12"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/floris.briolas.nl\/floris\/wp-json\/wp\/v2\/categories?post=12"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/floris.briolas.nl\/floris\/wp-json\/wp\/v2\/tags?post=12"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}