aboutsummaryrefslogtreecommitdiff
path: root/antlr-3.4/runtime/Delphi/README.TXT
blob: f29e9b1b6fa6251db7f6e4413fb5c43c3bb79e03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
==================================================
ANTLR v3 Delphi Code generator and Runtime library
==================================================

October 27, 2008
Erik van Bilsen (erik AT bilsen DOT com)

Please see LICENSE.TXT for the full text of the license and NOTICE.TXT
for attribution notices.

Architecture
============
The Delphi target consists of a set of code generation templates and a runtime 
library (written in Delphi 2009) for the Win32 platform.
The Delphi code generation targets and the runtime library are modeled on the 
C# version.

You need to use Delphi 2009 or a later version to be able to use this target. 
You will not be able to compile generated code with older versions of Delphi.
The reason for this is that this Delphi target uses a lot of new Delphi 
language features such as generics.

To use the Delphi target, you only need to put the runtime source code in a 
directory of your choice, and add this directory to you Delphi library path or 
to your project's search path.

The runtime consists of the following units:
-Antlr.Runtime: the main Antlr unit that contains the parser and lexer classes
-Antlr.Runtime.Tree: the tree parser class and other tree related classes
-Antlr.Runtime.Collections: several collection utilities
-Antlr.Runtime.Tools: this is a special Delphi addition to the runtime 
 containing several helper classes and utilities
You will find these files in the "Antlr3.Runtime" subdirectory.

In your projects, you usually only need to use the Antlr.Runtime unit, and the
Antlr.Runtime.Tree unit for tree parsers.
This target does not require any third party libraries, and you do not have to
deploy any DLLs or other files with your ANTLR Delphi projects.

Please note that this Delphi target does not support StringTemplate output, but
it does support all other output types, including AST output.

Status
======
As of October 2008, the Delphi target is in sync with ANTLR 3.1.

This version passes all the unit tests (which you can find in the
"Antlr3.Runtime.Tests" subdirectory) without any memory leaks.
Also, all the grammar samples in the "examples-v3\Delphi" directory function
correctly and without any memory leaks.

Performance
===========
This target should perform reasonably well compared to other ANTLR targets.
For some grammars, especially tree grammars, the code that is generated is not
as efficient as for other targets. This has to do with the way the code is
generated to work around some issues with the Delphi language. But even with
these workarounds, the target performs within reasonable boundaries.

Usage
=====
Here is a short list of Delphi specific issues you need to take into account
when using this target. Please check out the Delphi sample grammars in the
"examples-v3" archive for examples of all the issues described below. And these
examples are a great way to get started with ANTLR.

Specify that Delphi code should be generated for a grammar
----------------------------------------------------------
To specify that the ANTLR tool should generate Delphi (2009) code (rather than
the default of generating Java code) for a grammar, set the grammar-level option
named "language" to the value "Delphi" as shown below:

  grammar MyGrammar;

  options {
  	language=Delphi;
  }
  ...

For the example grammar named MyGrammar above, the grammar file would typically
be named MyGrammar.g. The grammar filename (excluding the extension) must match
the grammar name as declared with the grammar directive in the file.

Use Delphi code in actions
--------------------------
Obviously, any custom actions inside your grammars should be written in the
Delphi language. This also applies to less obvious actions like
{$channel=HIDDEN;}, which should be written as {$channel:=HIDDEN;} (with the
colon before the equals sign).

Rule names must not be case sensitive
-------------------------------------
Since the Delphi language is not case sensitive, you must take care that the
names of rules in your grammars differ by more than only case. For example, if
you have a parser rule called "expression", then you shouldn't have a lexer rule
called "EXPRESSION" or "Expression" or any other combination of upper- and lower
case characters that math the same word. ANTLR will still be able to generate
Delphi code for this, but you will not be able to compile it because of
duplicate identifiers.

The @members grammar action
---------------------------
The Delphi target does not recognize the default @members grammar action. It
uses the following three grammar actions instead (see the C and Java sample
grammars for examples):

@memberDeclarations: use this action that declare members in the generated
parser/lexer class. For example:

  @memberDeclarations {
	enumIsKeyword: Boolean;
	function isTypeName(const name: String): Boolean;
  }

  These declarations will appear inside the parser/lexer class declaration.

@memberInitializations: use this action to initialize variables declared in the
@memberDeclarations action. For example:

  @memberInitializations {
	enumIsKeyword := True;
  }

  These statements will appear inside the constructor of the parser/lexer class.

@memberImplementations: use this action for any code that must appear in the
parser class implementation. For example:

  @memberImplementations {
  function TCParser.isTypeName(const name: String): Boolean;
  begin
    Result := [...]
  end;
  }

  The code inside this action appears as-is inside the implementation section of
  the parser/lexer unit. This means that you need to specify the full name of
  the method, including the parser/lexer class name (eg. TCParser.isTypeName).
  The class name is based on the name of the grammar, and whether it is a parser
  or lexer. So, if your grammar is called "MyGrammar", then the lexer class will
  be called TMyGrammarLexer and the parser class will be called
  TMyGrammarParser.

The @vars grammar action
------------------------
ANTLR supports an @init (and @after) grammar action for any code you want to
execute at the beginning (or end) of a rule. If that code, or any other code
inside the rule, makes use of a local variable, then you need to declare that
variable first. The Delphi target adds the @vars grammar action for this
purpose. You can declare any local variables inside this action, as in this
example (taken from the Python example grammar):

  LEADING_WS
  @vars {
    spaces: Integer;
    S: String;
  }
  @init {
    spaces := 0;
  }

The variables you declare in the @vars action will appear inside the "var"
declaration block of the method for the rule (in this case for the
LEADING_WS rule).

The @usesInterface and @usedImplementation grammar actions
----------------------------------------------------------
If you need to add units to the uses clause of the generated units, then you can
use the @usesInterface and @usesImplementation grammar actions. For example, if
some code inside the grammer rules needs access to the Delphi TStringList class,
then you will need to use the Classes unit.
Use the @usesInterface action if you need the units to appear in the interface
part, or @usesImplementation if you only need a unit inside the implementation.
For example:

  @usesImplementation {
    Classes,
    Generics.Collections,
  }

Note that you need to add a comma after each unit in this list. The Delphi units
SysUtils, StrUtils and Math are added to the uses clause automatically.
Also note that you will usually put the @usesInterface/@usesImplementation
actions at the top of your grammar file, like you would the with the @header
action for other language targets.

The Delphi target is interface based
------------------------------------
All classes inside the Delphi ANTLR runtime use object interfaces. This greatly
simplifies memory management and makes using the runtime much easier. This means
that you will never declare class variables for ANTLR objects, but only use
interface variables. For example, a typical test rig in Delphi looks like this
(taken from the SimpleC example):

  procedure Run(const InputFilename: String);
  var
    Input: ICharStream;
    Lex: ISimpleCLexer;
    Tokens: ICommonTokenStream;
    Parser: ISimpleCParser;
    R: Iprog_return;
  begin
    Input := TANTLRFileStream.Create(InputFilename);
    Lex := TSimpleCLexer.Create(Input);
    Tokens := TCommonTokenStream.Create(Lex);
    Parser := TSimpleCParser.Create(Tokens);
    R := Parser.prog;
    WriteLn('tree=' + (R.Tree as ITree).ToStringTree);
  end;

Note that all variables are declared as interface variables (starting with a
capital I) instead of class variables (with a capital T). And there is no need
to destroy these objects yourself (there are no calls to Free and no
try..finally blocks to protect these resources).

If you are new to interface-based programming, then don't worry: just remember
to declare all ANTLR objects using interface variables, and don't call Free
on them.

Note that the C# and Java versions of the tree creation classes use the general
Object type for tree nodes. In the Delphi version, tree nodes are of type
IANTLRInterface, and can be implemented in various class (like TCommonTree).

Antlr.Runtime.Tools
-------------------
This unit contains some classes and interfaces you may find useful inside ANTLR
projects. Also, this unit contains declarations for the IANTLRInterface
interface and TANTLRObject class. All ANTLR classes derive from TANTLRObject and
implement the IANTLRInterface interface.

Other interfaces/classes you may find useful are:

* IANTLRString (implemented in TANTLRString): a wrapper around a Delphi string
  that allows you to treat a string as a regular ANTLR object.

* IList<T> (implemented in TList<T>): a generic list containing elements of
  type <T>. For example, you can create a list of Integers like this:

  var
    List: IList<Integer>;
  begin
    List := TList<Integer>.Create;
    List.Add(123);
  end;

  Note that this is basically the same TList<T> declared in Delphi's unit
  Generics.Collections, but it implements the IList<T> interface.

* IDictionary<TKey, TValue> (implemented in TDictionary<TKey, TValue>): a
  generic dictionary that maps elements of type <TKey> to <TValue>. For example,
  to map Strings to TANTLRObjects, use:

  var
    Map: IDictionary<String, IANTLRInterface>
  begin
    Map := TDictionary<String, IANTLRInterface>.Create;
    Map.Add('foo', TANTLRObject.Create);
  end;

  Again, this class is similar to Delphi's TDictionary, but it implements the
  IDictionary<TKey, TValue> interface.



Erik van Bilsen