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