1buildrec(3) ANTLR3C buildrec(3)
2
3
4
6 buildrec - How to build Generated C Code
7
9 The antlr tool jar, run against a grammar file that targets the C
10 language, will generate the following files according to whether your
11 grammar file contains a lexer, parser, combined or treeparser
12 specification. Your grammar file name and the subject of the grammar
13 line in your file are expected to match. Here the generic name G is
14 used:
15
16 Suffix Generated files lexer grammar (G.g3l) GLexer.c GLexer.h
17 parser grammar (G.g3p) GParser.c GParser.h grammar G (G.g3pl)
18 GParser.c GParser.h GLexer.c GLexer.h tree grammar G; (G.g3t) G.c G.h
19
20 The generated .c files reference the .h files using <G.h>, so you must
21 use -I. on your compiler command line (or include the current directory
22 in your include paths in Visual Studio). Additionally, the generated .h
23 files reference antlr3.h, so you must use -I/path/to/antlr/include
24 (E.g. -I /usr/local/include) to reference the standard ANTLR include
25 files.
26
27 In order to reference the library file at compile time (you can/should
28 only reference one) you need to use the -L/path/to/antlr/lib (E.g. -L
29 /usr/local/lib) on Unix, or add the path to your 'Additional Library
30 Path' in Visual Studio. You also need to specify the library using -L
31 on Unix (E.g. -L /usr/local/lib -l antlr3c) or add antlr3c_dll.lib to
32 your Additional Library Dependencies in Visual Studio.
33
34 In case it isn't obvious, the generated files may be used to produce
35 either a library or an executable (.EXE on Windows) file.
36
37 If you use the shared version of the libraries, DLL or .so/.so/.a then
38 you must ship the library with your application must run in an
39 environment whereby the library can be found by the runtime
40 linker/loader. This usually involves specifying the directory in which
41 the library lives to an environment variable. On Windows,
42 X:{yourwininstalldir}\system32 will be searched automatically.
43
45 In order to run your lexer/parser/tree parser combination, you will
46 need a small function (or main) function that controls the sequence of
47 events, from reading the input file or string, through to invoking the
48 tree parser(s) and retrieving the results. See 'Using the ANTLR3C C
49 Target' for more detailed instructions, but if you just want to get
50 going as fast as possible, study the following code example.
51
52 // You may adopt your own practices by all means, but in general it is best
53 // to create a single include for your project, that will include the ANTLR3 C
54 // runtime header files, the generated header files (all of which are safe to include
55 // multiple times) and your own project related header files. Use <> to include and
56 // -I on the compile line (which vs2005 now handles, where vs2003 did not).
57 //
58 #include <treeparser.h>
59
60 // Main entry point for this example
61 //
62 int ANTLR3_CDECL
63 main (int argc, char *argv[])
64 {
65 // Now we declare the ANTLR related local variables we need.
66 // Note that unless you are convinced you will never need thread safe
67 // versions for your project, then you should always create such things
68 // as instance variables for each invocation.
69 // -------------------
70
71 // Name of the input file. Note that we always use the abstract type pANTLR3_UINT8
72 // for ASCII/8 bit strings - the runtime library guarantees that this will be
73 // good on all platforms. This is a general rule - always use the ANTLR3 supplied
74 // typedefs for pointers/types/etc.
75 //
76 pANTLR3_UINT8 fName;
77
78 // The ANTLR3 character input stream, which abstracts the input source such that
79 // it is easy to privide inpput from different sources such as files, or
80 // memory strings.
81 //
82 // For an 8Bit/latin-1/etc memory string use:
83 // input = antlr3New8BitStringInPlaceStream (stringtouse, (ANTLR3_UINT32) length, NULL);
84 //
85 // For a UTF16 memory string use:
86 // input = antlr3NewUTF16StringInPlaceStream (stringtouse, (ANTLR3_UINT32) length, NULL);
87 //
88 // For input from a file, see code below
89 //
90 // Note that this is essentially a pointer to a structure containing pointers to functions.
91 // You can create your own input stream type (copy one of the existing ones) and override any
92 // individual function by installing your own pointer after you have created the standard
93 // version.
94 //
95 pANTLR3_INPUT_STREAM input;
96
97 // The lexer is of course generated by ANTLR, and so the lexer type is not upper case.
98 // The lexer is supplied with a pANTLR3_INPUT_STREAM from whence it consumes its
99 // input and generates a token stream as output. This is the ctx (CTX macro) pointer
100 // for your lexer.
101 //
102 pLangLexer lxr;
103
104 // The token stream is produced by the ANTLR3 generated lexer. Again it is a structure based
105 // API/Object, which you can customise and override methods of as you wish. a Token stream is
106 // supplied to the generated parser, and you can write your own token stream and pass this in
107 // if you wish.
108 //
109 pANTLR3_COMMON_TOKEN_STREAM tstream;
110
111 // The Lang parser is also generated by ANTLR and accepts a token stream as explained
112 // above. The token stream can be any source in fact, so long as it implements the
113 // ANTLR3_TOKEN_SOURCE interface. In this case the parser does not return anything
114 // but it can of course specify any kind of return type from the rule you invoke
115 // when calling it. This is the ctx (CTX macro) pointer for your parser.
116 //
117 pLangParser psr;
118
119 // The parser produces an AST, which is returned as a member of the return type of
120 // the starting rule (any rule can start first of course). This is a generated type
121 // based upon the rule we start with.
122 //
123 LangParser_decl_return langAST;
124
125
126 // The tree nodes are managed by a tree adaptor, which doles
127 // out the nodes upon request. You can make your own tree types and adaptors
128 // and override the built in versions. See runtime source for details and
129 // eventually the wiki entry for the C target.
130 //
131 pANTLR3_COMMON_TREE_NODE_STREAM nodes;
132
133 // Finally, when the parser runs, it will produce an AST that can be traversed by the
134 // the tree parser: c.f. LangDumpDecl.g3t This is the ctx (CTX macro) pointer for your
135 // tree parser.
136 //
137 pLangDumpDecl treePsr;
138
139 // Create the input stream based upon the argument supplied to us on the command line
140 // for this example, the input will always default to ./input if there is no explicit
141 // argument.
142 //
143 if (argc < 2 || argv[1] == NULL)
144 {
145 fName =(pANTLR3_UINT8)"./input"; // Note in VS2005 debug, working directory must be configured
146 }
147 else
148 {
149 fName = (pANTLR3_UINT8)argv[1];
150 }
151
152 // Create the input stream using the supplied file name
153 // (Use antlr38BitFileStreamNew for UTF16 input).
154 //
155 input = antlr38BitFileStreamNew(fName);
156
157 // The input will be created successfully, providing that there is enough
158 // memory and the file exists etc
159 //
160 if ( input == NULL )
161 {
162 ANTLR3_FPRINTF(stderr, "Unable to open file %s due to malloc() failure1\n", (char *)fName);
163 }
164
165 // Our input stream is now open and all set to go, so we can create a new instance of our
166 // lexer and set the lexer input to our input stream:
167 // (file | memory | ?) --> inputstream -> lexer --> tokenstream --> parser ( --> treeparser )?
168 //
169 lxr = LangLexerNew(input); // CLexerNew is generated by ANTLR
170
171 // Need to check for errors
172 //
173 if ( lxr == NULL )
174 {
175 ANTLR3_FPRINTF(stderr, "Unable to create the lexer due to malloc() failure1\n");
176 exit(ANTLR3_ERR_NOMEM);
177 }
178
179 // Our lexer is in place, so we can create the token stream from it
180 // NB: Nothing happens yet other than the file has been read. We are just
181 // connecting all these things together and they will be invoked when we
182 // call the parser rule. ANTLR3_SIZE_HINT can be left at the default usually
183 // unless you have a very large token stream/input. Each generated lexer
184 // provides a token source interface, which is the second argument to the
185 // token stream creator.
186 // Note tha even if you implement your own token structure, it will always
187 // contain a standard common token within it and this is the pointer that
188 // you pass around to everything else. A common token as a pointer within
189 // it that should point to your own outer token structure.
190 //
191 tstream = antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, lxr->pLexer->tokSource);
192
193 if (tstream == NULL)
194 {
195 ANTLR3_FPRINTF(stderr, "Out of memory trying to allocate token stream\n");
196 exit(ANTLR3_ERR_NOMEM);
197 }
198
199 // Finally, now that we have our lexer constructed, we can create the parser
200 //
201 psr = LangParserNew(tstream); // CParserNew is generated by ANTLR3
202
203 if (psr == NULL)
204 {
205 ANTLR3_FPRINTF(stderr, "Out of memory trying to allocate parser\n");
206 exit(ANTLR3_ERR_NOMEM);
207 }
208
209 // We are all ready to go. Though that looked complicated at first glance,
210 // I am sure, you will see that in fact most of the code above is dealing
211 // with errors and there isn;t really that much to do (isn;t this always the
212 // case in C? ;-).
213 //
214 // So, we now invoke the parser. All elements of ANTLR3 generated C components
215 // as well as the ANTLR C runtime library itself are pseudo objects. This means
216 // that they are represented as pointers to structures, which contain any
217 // instance data they need, and a set of pointers to other interfaces or
218 // 'methods'. Note that in general, these few pointers we have created here are
219 // the only things you will ever explicitly free() as everything else is created
220 // via factories, that allocate memory efficiently and free() everything they use
221 // automatically when you close the parser/lexer/etc.
222 //
223 // Note that this means only that the methods are always called via the object
224 // pointer and the first argument to any method, is a pointer to the structure itself.
225 // It also has the side advantage, if you are using an IDE such as VS2005 that can do it
226 // that when you type ->, you will see a list of all the methods the object supports.
227 //
228 langAST = psr->decl(psr);
229
230 // If the parser ran correctly, we will have a tree to parse. In general I recommend
231 // keeping your own flags as part of the error trapping, but here is how you can
232 // work out if there were errors if you are using the generic error messages
233 //
234 if (psr->pParser->rec->errorCount > 0)
235 {
236 ANTLR3_FPRINTF(stderr, "The parser returned %d errors, tree walking aborted.\n", psr->pParser->rec->errorCount);
237
238 }
239 else
240 {
241 nodes = antlr3CommonTreeNodeStreamNewTree(langAST.tree, ANTLR3_SIZE_HINT); // sIZE HINT WILL SOON BE DEPRECATED!!
242
243 // Tree parsers are given a common tree node stream (or your override)
244 //
245 treePsr = LangDumpDeclNew(nodes);
246
247 treePsr->decl(treePsr);
248 nodes ->free (nodes); nodes = NULL;
249 treePsr ->free (treePsr); treePsr = NULL;
250 }
251
252 // We did not return anything from this parser rule, so we can finish. It only remains
253 // to close down our open objects, in the reverse order we created them
254 //
255 psr ->free (psr); psr = NULL;
256 tstream ->free (tstream); tstream = NULL;
257 lxr ->free (lxr); lxr = NULL;
258 input ->close (input); input = NULL;
259
260 return 0;
261 }
262
263Version 3.3.1 Wed Jan 18 2023 buildrec(3)