source: trunk/idl-compiler/c/nom-idl-compiler.c@ 266

Last change on this file since 266 was 266, checked in by cinc, 18 years ago

Getting along with parsing

File size: 13.3 KB
Line 
1/* ***** BEGIN LICENSE BLOCK *****
2* Version: CDDL 1.0/LGPL 2.1
3*
4* The contents of this file are subject to the COMMON DEVELOPMENT AND
5* DISTRIBUTION LICENSE (CDDL) Version 1.0 (the "License"); you may not use
6* this file except in compliance with the License. You may obtain a copy of
7* the License at http://www.sun.com/cddl/
8*
9* Software distributed under the License is distributed on an "AS IS" basis,
10* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11* for the specific language governing rights and limitations under the
12* License.
13*
14* The Original Code is "NOM" Netlabs Object Model
15*
16* The Initial Developer of the Original Code is
17* netlabs.org: Chris Wohlgemuth <cinc-ml@netlabs.org>.
18* Portions created by the Initial Developer are Copyright (C) 2007
19* the Initial Developer. All Rights Reserved.
20*
21* Contributor(s):
22*
23* Alternatively, the contents of this file may be used under the terms of
24* the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
25* case the provisions of the LGPL are applicable instead of those above. If
26* you wish to allow use of your version of this file only under the terms of
27* the LGPL, and not to allow others to use your version of this file under
28* the terms of the CDDL, indicate your decision by deleting the provisions
29* above and replace them with the notice and other provisions required by the
30* LGPL. If you do not delete the provisions above, a recipient may use your
31* version of this file under the terms of any one of the CDDL or the LGPL.
32*
33* ***** END LICENSE BLOCK ***** */
34#define INCL_DOSPROCESS
35#define INCL_DOS
36#define INCL_DOSPROFILE
37#define INCL_DOSERRORS
38
39#include <os2.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43
44#include <io.h>
45#include <fcntl.h>
46#include <sys\stat.h>
47
48#include <glib.h>
49#include <glib/gprintf.h>
50
51#include "nom.h"
52#include "nomtk.h"
53
54#include "parser.h"
55
56static gchar* chrOutputDir="";
57static gchar* chrOutputName="";
58static gboolean fOptionEmitH=FALSE;
59static gboolean fOptionEmitIH=FALSE;
60static gboolean fOptionEmitC=FALSE;
61
62/* Command line options */
63static GOptionEntry gOptionEntries[] =
64{
65 {"directory", 'd', 0, G_OPTION_ARG_FILENAME, &chrOutputDir, "Output directory", NULL},
66 {"emit-h", 0, 0, G_OPTION_ARG_NONE, &fOptionEmitH, "Emmit a header file (*.h)", NULL},
67 {"emit-ih", 0, 0, G_OPTION_ARG_NONE, &fOptionEmitIH, "Emmit an include header (*.ih)", NULL},
68 {"emit-c", 0, 0, G_OPTION_ARG_NONE, &fOptionEmitC, "Emmit an implementation template (*.c)", NULL},
69 {"output", 'o', 0, G_OPTION_ARG_FILENAME, &chrOutputName, "Output name", NULL},
70 {NULL}
71};
72
73static char* chrOutputFileName="";
74
75/* The pointer array holding the interfaces we found */
76GPtrArray* pInterfaceArray;
77
78/* Symbols defined for our IDL language.
79 Keep this in synch with the defined enums! */
80SYMBOL idlSymbols[]={
81 {"interface", IDL_SYMBOL_INTERFACE, KIND_UNKNOWN}, /* 71 */
82 {"NOMCLASSVERSION", IDL_SYMBOL_CLSVERSION, KIND_UNKNOWN},
83 {"NOMINSTANCEVAR", IDL_SYMBOL_INSTANCEVAR, KIND_UNKNOWN},
84 {"NOMOVERRIDE", IDL_SYMBOL_OVERRIDE, KIND_UNKNOWN},
85 {"NOMREGISTEREDIFACE", IDL_SYMBOL_REGINTERFACE, KIND_TYPESPEC},
86 {"native", IDL_SYMBOL_NATIVE, KIND_UNKNOWN},
87 {"gulong", IDL_SYMBOL_GULONG, KIND_TYPESPEC},
88 {"gint", IDL_SYMBOL_GINT, KIND_TYPESPEC},
89 {"gpointer", IDL_SYMBOL_GPOINTER, KIND_TYPESPEC},
90 {"gboolean", IDL_SYMBOL_GBOOLEAN, KIND_TYPESPEC},
91 {"gchar", IDL_SYMBOL_GCHAR, KIND_TYPESPEC},
92 {"void", IDL_SYMBOL_VOID, KIND_TYPESPEC},
93 {"in", IDL_SYMBOL_IN, KIND_DIRECTION},
94 {"out", IDL_SYMBOL_OUT, KIND_DIRECTION},
95 {"inout", IDL_SYMBOL_INOUT, KIND_DIRECTION},
96 {"define", IDL_SYMBOL_DEFINE, KIND_UNKNOWN},
97 {"ifdef", IDL_SYMBOL_IFDEF, KIND_UNKNOWN},
98 {"endif", IDL_SYMBOL_ENDIF, KIND_UNKNOWN},
99 {NULL, 0, KIND_UNKNOWN}
100},*pSymbols=idlSymbols;
101
102GScanner *gScanner;
103GTokenType curToken=G_TOKEN_EOF;
104PINTERFACE pCurInterface=NULL;
105
106/* Holding info about current token. Referenced by gScanner. */
107SYMBOLINFO curSymbol;
108
109/* Holding the current state of parsing and pointers to necessary lists. */
110PARSEINFO parseInfo={0};
111
112PINTERFACE findInterfaceFromName(gchar* chrName)
113{
114 int a;
115
116 for(a=0;a<pInterfaceArray->len;a++)
117 {
118 PINTERFACE pif=g_ptr_array_index(pInterfaceArray, a);
119 if(!strcmp(chrName, pif->chrName))
120 return pif;
121 }
122
123 return NULL;
124}
125
126
127gchar* getTypeSpecStringFromCurToken(void)
128{
129 GTokenValue value;
130
131 value=gScanner->value;
132
133 switch(curToken)
134 {
135 case G_TOKEN_IDENTIFIER:
136 return g_strdup(value.v_identifier);
137 break;
138 case G_TOKEN_SYMBOL:
139 {
140 /* It's one of our symbols. */
141 PSYMBOL pCurSymbol;
142
143 pCurSymbol=value.v_symbol;
144 return g_strdup(pCurSymbol->chrSymbolName);
145 break;
146 }
147 default:
148 g_scanner_unexp_token(gScanner,
149 G_TOKEN_SYMBOL,
150 NULL,
151 NULL,
152 NULL,
153 "",
154 TRUE); /* is_error */
155
156 break;
157 }
158 return "unknown";
159}
160
161/*
162 The native keyword is used to introduce new types. That's coming
163 from the Corba spec. Maybe we will change that some time.
164
165The current token is the 'native' keyword.
166
167 N:= G_TOKEN_SYMBOL IDENT ';'
168 */
169static void parseNative(void)
170{
171 GTokenValue value;
172 PSYMBOL pCurSymbol=g_malloc0(sizeof(SYMBOL));
173
174 if(!matchNext(G_TOKEN_IDENTIFIER))
175 {
176 PSYMBOL pSymbol;
177
178 /* Check if it's a symbol. The following 'identifier' (word) is maybe alread
179 registered as a symbol. */
180 if(!matchNext(G_TOKEN_SYMBOL))
181 {
182 g_scanner_unexp_token(gScanner,
183 G_TOKEN_SYMBOL,
184 NULL,
185 NULL,
186 NULL,
187 "'native' statement is not followed by a valid identifier.",
188 TRUE); /* is_error */
189 exit(1);
190 }
191 /* It's a symbol. Check if it's a typespec. */
192 value=gScanner->value;
193 pSymbol=value.v_symbol;
194 if(!pSymbol || pSymbol->uiKind!=KIND_TYPESPEC)
195 {
196 g_scanner_unexp_token(gScanner,
197 G_TOKEN_SYMBOL,
198 NULL,
199 NULL,
200 NULL,
201 "'native' statement is not followed by a valid symbol.",
202 TRUE); /* is_error */
203 exit(1);
204 }
205 }
206
207 value=gScanner->value;
208 pCurSymbol->chrSymbolName=g_strdup(value.v_identifier);
209 pCurSymbol->uiKind=KIND_TYPESPEC;
210 pCurSymbol->uiSymbolToken=G_TOKEN_NONE;
211 g_tree_insert(parseInfo.pSymbolTree, pCurSymbol, pCurSymbol->chrSymbolName);
212 g_scanner_scope_add_symbol(gScanner, ID_SCOPE, pCurSymbol->chrSymbolName,
213 pCurSymbol);
214
215 if(!matchNext(';'))
216 {
217 getNextToken(); /* Make sure error references the correct token */
218 g_scanner_unexp_token(gScanner,
219 ';',
220 NULL,
221 NULL,
222 NULL,
223 "Error in 'native' definition , Missing semicolon",
224 TRUE); /* is_error */
225 exit(1);
226 }
227
228}
229
230/**
231 This is the root parse function. Here starts the fun...
232 */
233void parseIt(void)
234{
235 while(g_scanner_peek_next_token(gScanner) != G_TOKEN_EOF) {
236 GTokenType token;
237
238 curToken=g_scanner_get_next_token(gScanner);
239 token=curToken;
240 GTokenValue value=gScanner->value;
241
242 switch(curToken)
243 {
244 case '#':
245 parseHash();
246 break;
247 case G_TOKEN_SYMBOL:
248 {
249 PSYMBOL pCurSymbol=value.v_symbol;
250 switch(pCurSymbol->uiSymbolToken)
251 {
252 case IDL_SYMBOL_INTERFACE:
253 parseInterface(token);
254 break;
255 case IDL_SYMBOL_NATIVE:
256 parseNative();
257 break;
258 default:
259 break;
260 }
261 break;
262 }
263#if 0
264 case G_TOKEN_IDENTIFIER:
265 g_message("Token: %d (G_TOKEN_IDENTIFIER)\t\t%s", token, value.v_identifier);
266 break;
267 case G_TOKEN_STRING:
268 g_message("Token: %d (G_TOKEN_STRING)\t\t\t%s", token, value.v_string);
269 break;
270 case G_TOKEN_LEFT_PAREN:
271 g_message("Token: %d (G_TOKEN_LEFT_PAREN)\t\t(", token);
272 break;
273 case G_TOKEN_RIGHT_PAREN:
274 g_message("Token: %d (G_TOKEN_RIGHT_PAREN)\t\t)", token);
275 break;
276 case ':':
277 g_message("Token: %d (colon)\t\t:", token);
278 break;
279 case ';':
280 g_message("Token: %d (semicolon)\t\t\t;", token);
281 break;
282 case '/':
283 g_message("Token: %d (slash)\t\t\t/ %s", token, value.v_comment);
284 break;
285 case G_TOKEN_COMMA:
286 g_message("Token: %d (G_TOKEN_COMMA)\t\t\t,", token);
287 break;
288 case G_TOKEN_INT:
289 g_message("Token: %d (G_TOKEN_INT)\t\t\t%ld", token, value.v_int);
290 break;
291 case IDL_SYMBOL_DEFINE:
292 g_message("Token: %d (IDL_SYMBOL_DEFINE)\t\t\t", token);
293 break;
294 case IDL_SYMBOL_IFDEF:
295 g_message("Token: %d (IDL_SYMBOL_IFDEF)\t\t\t", token);
296 break;
297 case IDL_SYMBOL_ENDIF:
298 g_message("Token: %d (IDL_SYMBOL_ENDIF)\t\t\t", token);
299 break;
300#endif
301 default:
302 printToken(curToken);
303 break;
304 }
305 }
306}
307
308/* Show help.
309 gContext must be valid.
310*/
311static void outputCompilerHelp(GOptionContext *gContext, gchar* chrExeName)
312{
313 GError *gError = NULL;
314 int argc2=2;
315 char *helpCmd[]={"","--help"};
316 char** argv2=helpCmd;
317 helpCmd[0]=chrExeName;
318
319 g_option_context_parse (gContext, &argc2, &argv2, &gError);
320}
321
322/*
323 Compare function for the tree holding our private symbols.
324 */
325static gint funcSymbolCompare(gconstpointer a, gconstpointer b)
326{
327 if(a==b)
328 return 0;
329
330 if(a<b)
331 return -1;
332
333 return 1;
334};
335
336void funcMsgHandler(GScanner *gScanner,
337 gchar *message,
338 gboolean error)
339{
340
341 g_printf("In file %s, line %d:\n\t%s\n", parseInfo.chrCurrentSourceFile,
342 g_scanner_cur_line(gScanner)-parseInfo.uiLineCorrection, message);
343}
344
345/*
346
347 */
348int main(int argc, char **argv)
349{
350 int a;
351 int fd;
352
353 GError *gError = NULL;
354 GOptionContext* gContext;
355
356 /* Parse command line options */
357 gContext = g_option_context_new ("file");
358 g_option_context_add_main_entries (gContext, gOptionEntries, NULL);
359
360 if(!g_option_context_parse (gContext, &argc, &argv, &gError))
361 {
362 outputCompilerHelp(gContext, argv[0]);
363 }
364
365 /* Correct emitter options? Exactly one emitter must be specified. */
366 a=0;
367 if(fOptionEmitH)
368 a++;
369 if(fOptionEmitIH)
370 a++;
371 if(fOptionEmitC)
372 a++;
373
374#if 0
375 if(!a){
376 g_printf("An emitter must be specified.\n\n");
377 outputCompilerHelp(gContext, argv[0]);
378 }
379 if(a>1){
380 g_printf("Only one emitter must be specified.\n\n");
381 outputCompilerHelp(gContext, argv[0]);
382 }
383#endif
384 g_option_context_free(gContext);
385
386
387 if(argc<2)
388 {
389 g_printf("No input file name given.\n\nUse %s --help for options.\n\n", argv[0]);
390 return 1;
391 }
392
393 for(a=0; a<argc; a++)
394 {
395 g_message("arg %d: %s", a, argv[a]);
396 }
397
398 /* Create output file name */
399 if(!strcmp(argv[1], "-"))
400 fd=0; /* Read from stdin */
401 else
402 fd=open(argv[1], O_RDONLY);
403
404 if(-1==fd)
405 {
406 g_message("Can't open input file %s", argv[1]);
407 exit(1);
408 }
409
410 g_printf("\n");
411
412
413
414 gScanner=g_scanner_new(NULL);
415 gScanner->user_data=(gpointer)&curSymbol;
416 curSymbol.pSymbols=idlSymbols;
417
418 gScanner->msg_handler=funcMsgHandler;
419 pInterfaceArray=g_ptr_array_new();
420
421 g_scanner_input_file(gScanner, fd);
422 /* No single line comments */
423 gScanner->config->skip_comment_single=FALSE;
424 gScanner->config->cpair_comment_single="";
425 /* This string is used in error messages of the parser */
426 gScanner->input_name=IDL_COMPILER_STRING;
427
428 g_scanner_set_scope(gScanner, ID_SCOPE);
429 /* Load our own symbols into the scanner. We use the default scope for now. */
430 parseInfo.pSymbolTree=g_tree_new((GCompareFunc) funcSymbolCompare);
431 while(pSymbols->chrSymbolName)
432 {
433#warning !!! Create a copy here so it is the same as with new symbols added later.
434 g_scanner_scope_add_symbol(gScanner, ID_SCOPE, pSymbols->chrSymbolName,
435 pSymbols);
436 g_tree_insert(parseInfo.pSymbolTree, pSymbols, pSymbols->chrSymbolName);
437 pSymbols++;
438 }
439 // gScanner->config->symbol_2_token=TRUE;
440
441 parseIt();
442
443 if(pInterfaceArray->len)
444 printInterface();
445
446 g_scanner_destroy(gScanner);
447 close(fd);
448
449 return 0;
450}
451
452#if 0
453 /* We are a folder somwhere in the chain */
454 nomRetval=WPFileSystem_wpQueryFileName((WPFileSystem*)wpParent, bFullPath, NULLHANDLE);
455
456 nomRetval=wpParent.wpQueryFileName(bFullPath, NULLHANDLE);
457
458 nomPath=NOMPathNew();
459 nomPath= (PNOMPath) NOMPath_assignCString(nomPath, _pszFullPath, ev);
460
461 return (PNOMPath)NOMPath_appendPath(nomRetval, nomPath, NULLHANDLE);
462
463#endif
464
465
466
467
468
469
470
471
472
Note: See TracBrowser for help on using the repository browser.