Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>You first create a grammar. Below is a small grammar that you can use to evaluate expressions that are built using the 4 basic math operators: +, -, * and /. You can also group expressions using parenthesis.</p> <p>Note that this grammar is just a very basic one: it does not handle unary operators (the minus in: -1+9) or decimals like .99 (without a leading number), to name just two shortcomings. This is just an example you can work on yourself.</p> <p>Here's the contents of the grammar file <strong>Exp.g</strong>:</p> <pre><code>grammar Exp; /* This will be the entry point of our parser. */ eval : additionExp ; /* Addition and subtraction have the lowest precedence. */ additionExp : multiplyExp ( '+' multiplyExp | '-' multiplyExp )* ; /* Multiplication and division have a higher precedence. */ multiplyExp : atomExp ( '*' atomExp | '/' atomExp )* ; /* An expression atom is the smallest part of an expression: a number. Or when we encounter parenthesis, we're making a recursive call back to the rule 'additionExp'. As you can see, an 'atomExp' has the highest precedence. */ atomExp : Number | '(' additionExp ')' ; /* A number: can be an integer value, or a decimal value */ Number : ('0'..'9')+ ('.' ('0'..'9')+)? ; /* We're going to ignore all white space characters */ WS : (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;} ; </code></pre> <p><em>(Parser rules start with a lower case letter, and lexer rules start with a capital letter)</em></p> <p>After creating the grammar, you'll want to generate a parser and lexer from it. Download the <a href="http://www.antlr.org/download/antlr-3.2.jar" rel="noreferrer">ANTLR jar</a> and store it in the same directory as your grammar file.</p> <p>Execute the following command on your shell/command prompt:</p> <pre><code>java -cp antlr-3.2.jar org.antlr.Tool Exp.g </code></pre> <p>It should not produce any error message, and the files <strong>ExpLexer.java</strong>, <strong>ExpParser.java</strong> and <strong>Exp.tokens</strong> should now be generated.</p> <p>To see if it all works properly, create this test class:</p> <pre class="lang-java prettyprint-override"><code>import org.antlr.runtime.*; public class ANTLRDemo { public static void main(String[] args) throws Exception { ANTLRStringStream in = new ANTLRStringStream("12*(5-6)"); ExpLexer lexer = new ExpLexer(in); CommonTokenStream tokens = new CommonTokenStream(lexer); ExpParser parser = new ExpParser(tokens); parser.eval(); } } </code></pre> <p>and compile it:</p> <pre><code>// *nix/MacOS javac -cp .:antlr-3.2.jar ANTLRDemo.java // Windows javac -cp .;antlr-3.2.jar ANTLRDemo.java </code></pre> <p>and then run it:</p> <pre><code>// *nix/MacOS java -cp .:antlr-3.2.jar ANTLRDemo // Windows java -cp .;antlr-3.2.jar ANTLRDemo </code></pre> <p>If all goes well, nothing is being printed to the console. This means the parser did not find any error. When you change <code>"12*(5-6)"</code> into <code>"12*(5-6"</code> and then recompile and run it, there should be printed the following:</p> <pre><code>line 0:-1 mismatched input '&lt;EOF&gt;' expecting ')' </code></pre> <p>Okay, now we want to add a bit of Java code to the grammar so that the parser actually does something useful. Adding code can be done by placing <code>{</code> and <code>}</code> inside your grammar with some plain Java code inside it.</p> <p>But first: all parser rules in the grammar file should return a primitive double value. You can do that by adding <code>returns [double value]</code> after each rule:</p> <pre><code>grammar Exp; eval returns [double value] : additionExp ; additionExp returns [double value] : multiplyExp ( '+' multiplyExp | '-' multiplyExp )* ; // ... </code></pre> <p>which needs little explanation: every rule is expected to return a double value. Now to "interact" with the return value <code>double value</code> (which is NOT inside a plain Java code block <code>{...}</code>) from inside a code block, you'll need to add a dollar sign in front of <code>value</code>:</p> <pre><code>grammar Exp; /* This will be the entry point of our parser. */ eval returns [double value] : additionExp { /* plain code block! */ System.out.println("value equals: "+$value); } ; // ... </code></pre> <p>Here's the grammar but now with the Java code added:</p> <pre><code>grammar Exp; eval returns [double value] : exp=additionExp {$value = $exp.value;} ; additionExp returns [double value] : m1=multiplyExp {$value = $m1.value;} ( '+' m2=multiplyExp {$value += $m2.value;} | '-' m2=multiplyExp {$value -= $m2.value;} )* ; multiplyExp returns [double value] : a1=atomExp {$value = $a1.value;} ( '*' a2=atomExp {$value *= $a2.value;} | '/' a2=atomExp {$value /= $a2.value;} )* ; atomExp returns [double value] : n=Number {$value = Double.parseDouble($n.text);} | '(' exp=additionExp ')' {$value = $exp.value;} ; Number : ('0'..'9')+ ('.' ('0'..'9')+)? ; WS : (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;} ; </code></pre> <p>and since our <code>eval</code> rule now returns a double, change your ANTLRDemo.java into this:</p> <pre class="lang-java prettyprint-override"><code>import org.antlr.runtime.*; public class ANTLRDemo { public static void main(String[] args) throws Exception { ANTLRStringStream in = new ANTLRStringStream("12*(5-6)"); ExpLexer lexer = new ExpLexer(in); CommonTokenStream tokens = new CommonTokenStream(lexer); ExpParser parser = new ExpParser(tokens); System.out.println(parser.eval()); // print the value } } </code></pre> <p>Again (re) generate a fresh lexer and parser from your grammar (1), compile all classes (2) and run ANTLRDemo (3):</p> <pre><code>// *nix/MacOS java -cp antlr-3.2.jar org.antlr.Tool Exp.g // 1 javac -cp .:antlr-3.2.jar ANTLRDemo.java // 2 java -cp .:antlr-3.2.jar ANTLRDemo // 3 // Windows java -cp antlr-3.2.jar org.antlr.Tool Exp.g // 1 javac -cp .;antlr-3.2.jar ANTLRDemo.java // 2 java -cp .;antlr-3.2.jar ANTLRDemo // 3 </code></pre> <p>and you'll now see the outcome of the expression <code>12*(5-6)</code> printed to your console!</p> <p>Again: this is a very brief explanation. I encourage you to browse the <a href="http://www.antlr.org/wiki/display/ANTLR3/ANTLR+3+Wiki+Home" rel="noreferrer">ANTLR wiki</a> and read some tutorials and/or play a bit with what I just posted.</p> <p>Good luck!</p> <p>EDIT:</p> <p><a href="https://stackoverflow.com/questions/2042353/extending-simple-antlr-grammer-to-support-input-variables">This post</a> shows how to extend the example above so that a <code>Map&lt;String, Double&gt;</code> can be provided that holds variables in the provided expression.</p> <p>And this <a href="https://stackoverflow.com/questions/15610183/if-else-statements-in-antlr-using-listeners">Q&amp;A</a> demonstrates how to create a simple expression parser, and evaluator using <strong>ANTLR4</strong>.</p> <p>To get this code working with a current version of Antlr (June 2014) I needed to make a few changes. <code>ANTLRStringStream</code> needed to become <code>ANTLRInputStream</code>, the returned value needed to change from <code>parser.eval()</code> to <code>parser.eval().value</code>, and I needed to remove the <code>WS</code> clause at the end, because attribute values such as <code>$channel</code> are no longer allowed to appear in lexer actions.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload