• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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