{"id":8587,"date":"2020-11-01T20:55:56","date_gmt":"2020-11-01T20:55:56","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=8587"},"modified":"2020-11-01T21:41:31","modified_gmt":"2020-11-01T21:41:31","slug":"starting-out-with-antlr","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/starting-out-with-antlr\/","title":{"rendered":"Starting out with ANTLR"},"content":{"rendered":"<p>ANTLR (ANother Tool for Language Recognition) is a parser generator.<\/p>\n<p>You might be designing your own programming\/scripting language or defining something a little simpler, such as query language for your application or even just something to parse user input (which is not necessarily simpler). <\/p>\n<p>ANTLR can be downloaded from <a href=\"https:\/\/www.antlr.org\/download.html\" rel=\"noopener noreferrer\" target=\"_blank\">here<\/a> and whilst the tool itself is written in Java it can generate parser code in Java, C#, Python, JavaScript and more. <\/p>\n<p><em>Note: I&#8217;ve downloaded the &#8220;Complete ANTLR 4.8 Java binaries jar&#8221; hence the commands listed will all be in relation to that JAR.<\/em><\/p>\n<p><strong>Grammar files<\/strong><\/p>\n<p>Before we can do anything meaningful with ANTLR we need to define a grammar for our lexer and  parser to be generated from. These are text files with the extension .g or .g4 (for ANTLR 4 compatible grammars) and looks lot like BNF. Let&#8217;s create a grammar for a very simple query language that we&#8217;d like to incorporate into an application. <\/p>\n<p>We start by creating a file named querylanguage.g4<\/p>\n<p>I&#8217;m using Visual Studio Code to write the grammar and using the excellent <em>ANTLR4 grammar syntax support<\/em> extension to aid in developing the grammar.<\/p>\n<p>The first thing we add to the grammar is <\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\ngrammar querylanguage;\r\n<\/pre>\n<p>The grammar name must match the name of your grammar file. It can be prefixed with <em>lexer<\/em> or <em>parser<\/em> if you want to write grammar specific to either a lexer or parser, without these we&#8217;re creating a combined lexer and parser grammar. <\/p>\n<p>Here&#8217;s all the options for the grammar keyword.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nlexer grammar querylanguage;\r\n\r\n\/\/ or\r\n\r\nparser grammar querylanguage;\r\n\r\n\/\/ or \r\n\r\ngrammar querylanguage;\r\n<\/pre>\n<p>Before we extend our grammar let&#8217;s talk about comments &#8211; single line comments can be created using \/\/ and multi line using \/* *\/.<\/p>\n<p>We create our grammar using a combination of rules and tokens. Rules should be declared using camelCase whereas tokens should be all upper case. We&#8217;ll need an entry point (or start rule) so let&#8217;s extend our grammar within a start rule named <em>query<\/em> and this will be made up of an expression rule. We&#8217;ll also add a token to handle string types.<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\ngrammar querylanguage;\r\n\r\nquery\r\n    : expression\r\n    ;\r\n\r\nexpression\r\n    : STRING\r\n    | NUMBER\r\n    ;\r\n\r\nSTRING : '&quot;' .*? '&quot;';\r\nSIGN\r\n   : ('+' | '-')\r\n   ;\r\nNUMBER  \r\n    : SIGN? ( &#x5B;0-9]* '.' )? &#x5B;0-9]+;\r\n<\/pre>\n<p><em>We&#8217;ll look at the syntax of our rules etc. in a moment.<\/em><\/p>\n<p>As you can see, a rule is made up of a name followed by a colon and then either another rule or token and finally a rule or token is terminated with a ;. Alternate rules or tokens are defined using the | operator. So in the example above we have two token rules, query and expression and three tokens rules, STRING, SIGN and NUMBER. <\/p>\n<p>If we input &#8220;Hello World&#8221; then the ANTLR tokenize and parse this as a STRING. If we input 1234 then we&#8217;ll see this tokenize and parsed as a NUMBER. We can now start to build up our grammar from these basic building blocks, so let&#8217;s add some logic operators, AND and OR. We&#8217;ll also add a token rule to deal with whitespace characters (which we want to ignore). So change\/add the following to the existing grammar<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nexpression\r\n    : STRING\r\n    | NUMBER\r\n    | expression 'AND' expression\r\n    | expression 'OR' expression\r\n    ;\r\n\r\nWS  : (' '|'\\t'|'\\r'|'\\n')+ -&gt; skip;\r\n<\/pre>\n<p>WS is a special token rule which basically skips\/ignores the various whitespace characters.<\/p>\n<p>Let&#8217;s now take a look at the rule syntax we&#8217;ve used. <\/p>\n<ul>\n<li>&#8216; &#8216; &#8211; we denote literals within single quotes, so our previous declaration of a STRING show that a string starts with a string literal double quote and ends with the same.<\/li>\n<li>| &#8211; this is used to give alternate options, so the WS token rule is a &#8216; &#8216; OR &#8216;\\t&#8217; OR&#8230;<\/li>\n<li>(&#8230;) &#8211; this brackets acts as a subrule or grouping, so in this case of the WS token rule, we&#8217;re simply creating a group of white space characters following by a +, hence the + acts upon the group of characters<\/li>\n<li>+ &#8211; the + sign means 1 or more, hence for the WS token rule we&#8217;re saying the WS is 1 or more of any of the supplied literal characters.<\/li>\n<li>-> &#8211; this means rewrite this rule, in the case of WS this basically rewrites the rules to skip (which simply means ignore WS characters<\/li>\n<li>. &#8211; the dot is a wildcard, so in the STRING example we&#8217;re simply saying match any character<\/li>\n<li>* &#8211; this means zero or more, in the STRING example when applied to the ., i.e. .* we&#8217;re saying a string is 0 or more of any character<\/li>\n<li>? &#8211; means optional, an example is the use of SIGN? which simply means a SIGN is optional<\/li>\n<li>[&#8230;] &#8211; square brackets denote a character set, for example [0-9] means characters 0 through to 9 inclusive<\/li>\n<\/ul>\n<p>See <a href=\"https:\/\/theantlrguy.atlassian.net\/wiki\/spaces\/ANTLR3\/pages\/2687027\/Grammars\" rel=\"noopener noreferrer\" target=\"_blank\">Grammars<\/a> for the rest of the Grammar syntax.<\/p>\n<p>Another interesting keyword is <em>fragment<\/em>, for example<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nHexLiteral : '0' ('x'|'X') HexDigit+ ;\r\nfragment HexDigit : ('0'..'9'|'a'..'f'|'A'..'F') ;\r\n<\/pre>\n<p>A fragment is a modifier which doesn&#8217;t result in a token being visible to the parser but is more like an inline rule, in that it&#8217;s used &#8220;inline&#8221; within other rules, what if gives us is a way to create more reusable constructs and is useful if we want to share rules amongst other rules or to just make rules more readable.<\/p>\n<p><strong>Reserved keywords<\/strong><\/p>\n<p>ANTLR4 includes the following reserved words<\/p>\n<p><em><br \/>\nimport, fragment, lexer, parser, grammar, returns,<br \/>\nlocals, throws, catch, finally, mode, options, tokens<br \/>\n<\/em><\/p>\n<p>So obviously you cannot use these for your own rule names.<\/p>\n<p><strong>Debugging our grammar with the VS Code, ANTLR4 grammar syntax support extension<\/strong><\/p>\n<p>This <a href=\"https:\/\/github.com\/mike-lischke\/vscode-antlr4\" rel=\"noopener noreferrer\" target=\"_blank\">extension<\/a> is really useful when working with our grammars. First off we have syntax highlight and auto completion, which is always useful but it also includes a debugger and can display ANTLR exceptions when we&#8217;re not matching tokens or rules.<\/p>\n<p>To debug your grammar in VS Code, either editor your launch.json or add a configuration via Run | Add Configuration, here&#8217;s the configuration for testing our grammar<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n&quot;version&quot;: &quot;0.2.0&quot;,\r\n&quot;configurations&quot;: &#x5B;\r\n  {\r\n    &quot;name&quot;: &quot;Debug ANTLR4 grammar&quot;,\r\n    &quot;type&quot;: &quot;antlr-debug&quot;,\r\n    &quot;request&quot;: &quot;launch&quot;,\r\n    &quot;input&quot;: &quot;sample.txt&quot;,\r\n    &quot;grammar&quot;: &quot;querylanguage.g4&quot;,\r\n    &quot;startRule&quot;: &quot;query&quot;,\r\n    &quot;printParseTree&quot;: true,\r\n    &quot;visualParseTree&quot;: true\r\n  }\r\n]\r\n<\/pre>\n<p>You&#8217;re might want to change the &#8220;input&#8221; file to a named file of your choice, but basically this is just a text file where we put our test to be parsed via the grammar, so for example my sample.text file looks like this<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n&quot;HELLO&quot; AND 123\r\n<\/pre>\n<p>The &#8220;startRule&#8221; is the top level rule we want to parse our input through, so in our example it&#8217;s the <em>query<\/em> rule. Ofcourse we also need to tell the antrl-debug the &#8220;grammar&#8221; to use.<\/p>\n<p>Now in VS code press the run button using this configuration and you&#8217;ll get to see the output of the parse tree, for example<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nParse Tree:\r\nquery (\r\n expression (\r\n  expression (\r\n   &quot;&quot;HELLO&quot;&quot;\r\n  )\r\n  &quot;AND&quot;\r\n  expression (\r\n   &quot;123&quot;\r\n  )\r\n )\r\n)\r\n<\/pre>\n<p>There&#8217;s also a lovely parse tree so you can see how your grammar was parsed and which rules matched to which input.<\/p>\n<p><strong>Generating code<\/strong><\/p>\n<p>Everything we&#8217;ve looked at is great, but ofcourse we&#8217;ll want to actually include our grammar within our application and ANTLR comes to help by allowing us to use the previously downloaded JAR to generate the code for our preferred (and ofcourse supported) language.<\/p>\n<p>By default if you run<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\njava -jar antlr-4.8-complete.jar .\\querylanguage.g4\r\n<\/pre>\n<p>Then you&#8217;ll get a set of files produced which include Java source files for a Lexer, Parser and Listener. If you want to generate a Visitor then add the -visitor switch, like this<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\njava -jar antlr-4.8-complete.jar -visitor .\\querylanguage.g4  \r\n<\/pre>\n<p>As I&#8217;m wanting to generate C# source files, we can simply add the -Dlanguage switch, for example<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\njava -jar antlr-4.8-complete.jar -visitor -Dlanguage=CSharp .\\querylanguage.g4\r\n<\/pre>\n<p>But sadly <strong>this doesn&#8217;t work<\/strong>. It seems that whilst the JAR supports generating C# code the ANTLR .NET package is not compatible. In another post we&#8217;ll look at how we can generate C# code from our grammar.<\/p>\n<p><strong>References<\/strong><\/p>\n<p><a href=\"https:\/\/github.com\/antlr\/antlr4\/blob\/master\/doc\/tool-options.md\" rel=\"noopener noreferrer\" target=\"_blank\">ANTLR Tool Command Line Options<\/a><br \/>\n<a href=\"https:\/\/github.com\/antlr\/antlr4\/blob\/master\/doc\/index.md\" rel=\"noopener noreferrer\" target=\"_blank\">ANTLR 4 Documentation<\/a><br \/>\n<a href=\"https:\/\/github.com\/mike-lischke\/vscode-antlr4\" rel=\"noopener noreferrer\" target=\"_blank\">vscode-antlr4<\/a><br \/>\n<a href=\"https:\/\/github.com\/antlr\/grammars-v4\" rel=\"noopener noreferrer\" target=\"_blank\">Sample grammars<\/a><br \/>\n<a href=\"https:\/\/theantlrguy.atlassian.net\/wiki\/spaces\/ANTLR3\/pages\/2687027\/Grammars\" rel=\"noopener noreferrer\" target=\"_blank\">Grammars<\/a><br \/>\n<a href=\"https:\/\/theantlrguy.atlassian.net\/wiki\/spaces\/ANTLR3\/pages\/2687036\/ANTLR+Cheat+Sheet\" rel=\"noopener noreferrer\" target=\"_blank\">Cheat Sheet<\/a><br \/>\n<a href=\"https:\/\/github.com\/antlr\/antlr4\/blob\/master\/doc\/lexer-rules.md\" rel=\"noopener noreferrer\" target=\"_blank\">Lexer Rules<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>ANTLR (ANother Tool for Language Recognition) is a parser generator. You might be designing your own programming\/scripting language or defining something a little simpler, such as query language for your application or even just something to parse user input (which is not necessarily simpler). ANTLR can be downloaded from here and whilst the tool itself [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[310],"tags":[],"class_list":["post-8587","post","type-post","status-publish","format-standard","hentry","category-antlr"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/8587","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=8587"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/8587\/revisions"}],"predecessor-version":[{"id":8606,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/8587\/revisions\/8606"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=8587"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=8587"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=8587"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}