1================================================== 2ANTLR v3 Delphi Code generator and Runtime library 3================================================== 4 5October 27, 2008 6Erik van Bilsen (erik AT bilsen DOT com) 7 8Please see LICENSE.TXT for the full text of the license and NOTICE.TXT 9for attribution notices. 10 11Architecture 12============ 13The Delphi target consists of a set of code generation templates and a runtime 14library (written in Delphi 2009) for the Win32 platform. 15The Delphi code generation targets and the runtime library are modeled on the 16C# version. 17 18You need to use Delphi 2009 or a later version to be able to use this target. 19You will not be able to compile generated code with older versions of Delphi. 20The reason for this is that this Delphi target uses a lot of new Delphi 21language features such as generics. 22 23To use the Delphi target, you only need to put the runtime source code in a 24directory of your choice, and add this directory to you Delphi library path or 25to your project's search path. 26 27The runtime consists of the following units: 28-Antlr.Runtime: the main Antlr unit that contains the parser and lexer classes 29-Antlr.Runtime.Tree: the tree parser class and other tree related classes 30-Antlr.Runtime.Collections: several collection utilities 31-Antlr.Runtime.Tools: this is a special Delphi addition to the runtime 32 containing several helper classes and utilities 33You will find these files in the "Antlr3.Runtime" subdirectory. 34 35In your projects, you usually only need to use the Antlr.Runtime unit, and the 36Antlr.Runtime.Tree unit for tree parsers. 37This target does not require any third party libraries, and you do not have to 38deploy any DLLs or other files with your ANTLR Delphi projects. 39 40Please note that this Delphi target does not support StringTemplate output, but 41it does support all other output types, including AST output. 42 43Status 44====== 45As of October 2008, the Delphi target is in sync with ANTLR 3.1. 46 47This version passes all the unit tests (which you can find in the 48"Antlr3.Runtime.Tests" subdirectory) without any memory leaks. 49Also, all the grammar samples in the "examples-v3\Delphi" directory function 50correctly and without any memory leaks. 51 52Performance 53=========== 54This target should perform reasonably well compared to other ANTLR targets. 55For some grammars, especially tree grammars, the code that is generated is not 56as efficient as for other targets. This has to do with the way the code is 57generated to work around some issues with the Delphi language. But even with 58these workarounds, the target performs within reasonable boundaries. 59 60Usage 61===== 62Here is a short list of Delphi specific issues you need to take into account 63when using this target. Please check out the Delphi sample grammars in the 64"examples-v3" archive for examples of all the issues described below. And these 65examples are a great way to get started with ANTLR. 66 67Specify that Delphi code should be generated for a grammar 68---------------------------------------------------------- 69To specify that the ANTLR tool should generate Delphi (2009) code (rather than 70the default of generating Java code) for a grammar, set the grammar-level option 71named "language" to the value "Delphi" as shown below: 72 73 grammar MyGrammar; 74 75 options { 76 language=Delphi; 77 } 78 ... 79 80For the example grammar named MyGrammar above, the grammar file would typically 81be named MyGrammar.g. The grammar filename (excluding the extension) must match 82the grammar name as declared with the grammar directive in the file. 83 84Use Delphi code in actions 85-------------------------- 86Obviously, any custom actions inside your grammars should be written in the 87Delphi language. This also applies to less obvious actions like 88{$channel=HIDDEN;}, which should be written as {$channel:=HIDDEN;} (with the 89colon before the equals sign). 90 91Rule names must not be case sensitive 92------------------------------------- 93Since the Delphi language is not case sensitive, you must take care that the 94names of rules in your grammars differ by more than only case. For example, if 95you have a parser rule called "expression", then you shouldn't have a lexer rule 96called "EXPRESSION" or "Expression" or any other combination of upper- and lower 97case characters that math the same word. ANTLR will still be able to generate 98Delphi code for this, but you will not be able to compile it because of 99duplicate identifiers. 100 101The @members grammar action 102--------------------------- 103The Delphi target does not recognize the default @members grammar action. It 104uses the following three grammar actions instead (see the C and Java sample 105grammars for examples): 106 107@memberDeclarations: use this action that declare members in the generated 108parser/lexer class. For example: 109 110 @memberDeclarations { 111 enumIsKeyword: Boolean; 112 function isTypeName(const name: String): Boolean; 113 } 114 115 These declarations will appear inside the parser/lexer class declaration. 116 117@memberInitializations: use this action to initialize variables declared in the 118@memberDeclarations action. For example: 119 120 @memberInitializations { 121 enumIsKeyword := True; 122 } 123 124 These statements will appear inside the constructor of the parser/lexer class. 125 126@memberImplementations: use this action for any code that must appear in the 127parser class implementation. For example: 128 129 @memberImplementations { 130 function TCParser.isTypeName(const name: String): Boolean; 131 begin 132 Result := [...] 133 end; 134 } 135 136 The code inside this action appears as-is inside the implementation section of 137 the parser/lexer unit. This means that you need to specify the full name of 138 the method, including the parser/lexer class name (eg. TCParser.isTypeName). 139 The class name is based on the name of the grammar, and whether it is a parser 140 or lexer. So, if your grammar is called "MyGrammar", then the lexer class will 141 be called TMyGrammarLexer and the parser class will be called 142 TMyGrammarParser. 143 144The @vars grammar action 145------------------------ 146ANTLR supports an @init (and @after) grammar action for any code you want to 147execute at the beginning (or end) of a rule. If that code, or any other code 148inside the rule, makes use of a local variable, then you need to declare that 149variable first. The Delphi target adds the @vars grammar action for this 150purpose. You can declare any local variables inside this action, as in this 151example (taken from the Python example grammar): 152 153 LEADING_WS 154 @vars { 155 spaces: Integer; 156 S: String; 157 } 158 @init { 159 spaces := 0; 160 } 161 162The variables you declare in the @vars action will appear inside the "var" 163declaration block of the method for the rule (in this case for the 164LEADING_WS rule). 165 166The @usesInterface and @usedImplementation grammar actions 167---------------------------------------------------------- 168If you need to add units to the uses clause of the generated units, then you can 169use the @usesInterface and @usesImplementation grammar actions. For example, if 170some code inside the grammer rules needs access to the Delphi TStringList class, 171then you will need to use the Classes unit. 172Use the @usesInterface action if you need the units to appear in the interface 173part, or @usesImplementation if you only need a unit inside the implementation. 174For example: 175 176 @usesImplementation { 177 Classes, 178 Generics.Collections, 179 } 180 181Note that you need to add a comma after each unit in this list. The Delphi units 182SysUtils, StrUtils and Math are added to the uses clause automatically. 183Also note that you will usually put the @usesInterface/@usesImplementation 184actions at the top of your grammar file, like you would the with the @header 185action for other language targets. 186 187The Delphi target is interface based 188------------------------------------ 189All classes inside the Delphi ANTLR runtime use object interfaces. This greatly 190simplifies memory management and makes using the runtime much easier. This means 191that you will never declare class variables for ANTLR objects, but only use 192interface variables. For example, a typical test rig in Delphi looks like this 193(taken from the SimpleC example): 194 195 procedure Run(const InputFilename: String); 196 var 197 Input: ICharStream; 198 Lex: ISimpleCLexer; 199 Tokens: ICommonTokenStream; 200 Parser: ISimpleCParser; 201 R: Iprog_return; 202 begin 203 Input := TANTLRFileStream.Create(InputFilename); 204 Lex := TSimpleCLexer.Create(Input); 205 Tokens := TCommonTokenStream.Create(Lex); 206 Parser := TSimpleCParser.Create(Tokens); 207 R := Parser.prog; 208 WriteLn('tree=' + (R.Tree as ITree).ToStringTree); 209 end; 210 211Note that all variables are declared as interface variables (starting with a 212capital I) instead of class variables (with a capital T). And there is no need 213to destroy these objects yourself (there are no calls to Free and no 214try..finally blocks to protect these resources). 215 216If you are new to interface-based programming, then don't worry: just remember 217to declare all ANTLR objects using interface variables, and don't call Free 218on them. 219 220Note that the C# and Java versions of the tree creation classes use the general 221Object type for tree nodes. In the Delphi version, tree nodes are of type 222IANTLRInterface, and can be implemented in various class (like TCommonTree). 223 224Antlr.Runtime.Tools 225------------------- 226This unit contains some classes and interfaces you may find useful inside ANTLR 227projects. Also, this unit contains declarations for the IANTLRInterface 228interface and TANTLRObject class. All ANTLR classes derive from TANTLRObject and 229implement the IANTLRInterface interface. 230 231Other interfaces/classes you may find useful are: 232 233* IANTLRString (implemented in TANTLRString): a wrapper around a Delphi string 234 that allows you to treat a string as a regular ANTLR object. 235 236* IList<T> (implemented in TList<T>): a generic list containing elements of 237 type <T>. For example, you can create a list of Integers like this: 238 239 var 240 List: IList<Integer>; 241 begin 242 List := TList<Integer>.Create; 243 List.Add(123); 244 end; 245 246 Note that this is basically the same TList<T> declared in Delphi's unit 247 Generics.Collections, but it implements the IList<T> interface. 248 249* IDictionary<TKey, TValue> (implemented in TDictionary<TKey, TValue>): a 250 generic dictionary that maps elements of type <TKey> to <TValue>. For example, 251 to map Strings to TANTLRObjects, use: 252 253 var 254 Map: IDictionary<String, IANTLRInterface> 255 begin 256 Map := TDictionary<String, IANTLRInterface>.Create; 257 Map.Add('foo', TANTLRObject.Create); 258 end; 259 260 Again, this class is similar to Delphi's TDictionary, but it implements the 261 IDictionary<TKey, TValue> interface. 262 263 264 265Erik van Bilsen 266