]> git.draconx.ca Git - gob-dx.git/blob - src/lexer.l
Release 1.0.12
[gob-dx.git] / src / lexer.l
1 /* GOB C Preprocessor
2  * Copyright (C) 1999 the Free Software Foundation.
3  *
4  * Author: George Lebl
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the  Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19  * USA.
20  */
21 %{
22
23 #include "config.h"
24 #include <glib.h>
25 #include <string.h>
26 #include <ctype.h>
27
28 #include "treefuncs.h"
29 #include "parse.h"
30 #include "main.h"
31 #include "util.h"
32
33 static int parenth_depth = 0;
34 static int before_comment = INITIAL;
35 static gboolean class_after_c = FALSE;
36 static int code_type = CCODE;
37
38 /* GTK+ doc stuff */
39 static char *gtk_doc_func = NULL; /* current gtk-doc func */
40 GHashTable *gtk_doc_hash = NULL;
41
42 static GString *cbuf = NULL;
43 int ccode_line = 1;
44
45 GList *include_files = NULL;
46 /* 0 no, 1 means yes, 2+ means don't even start looking anymore */
47 static int look_for_includes = 0;
48
49 int line_no = 1;
50 /* last filename parsed from a #line directive */
51 char *hline_filename = NULL;
52
53 static void
54 clear_cbuf(void)
55 {
56         if(!cbuf) {
57                 cbuf = g_string_new(NULL);
58         } else {
59                 cbuf = g_string_assign(cbuf, "");
60         }
61 }
62
63 static void
64 add_to_cbuf(char *s)
65 {
66         if(!cbuf) {
67                 cbuf = g_string_new(s);
68         } else {
69                 cbuf = g_string_append(cbuf,s);
70         }
71 }
72
73 static void
74 add_gtk_doc_func(void)
75 {
76         if(!gtk_doc_func)
77                 return;
78
79         if(!gtk_doc_hash)
80                 gtk_doc_hash = g_hash_table_new(g_str_hash, g_str_equal);
81         g_hash_table_insert(gtk_doc_hash, gtk_doc_func, g_strdup(cbuf->str));
82         clear_cbuf();
83
84         gtk_doc_func = NULL;
85 }
86
87 /* Ugly warning avoiding */
88 #ifdef FLEX_SCANNER
89 int yylex(void);
90 #endif
91
92 %}
93
94 %x COMMENT
95 %x C_CODE
96 %x C_CODE_STRING
97 %x CLASS_CODE
98 %x CLASS_CODE_I
99 %x GTK_DOC_BEFORE_NAME
100 %x GTK_DOC
101 %x GTK_DOC_LINE
102
103
104
105 %%
106
107 <*>\n                   { line_no++; REJECT; }
108
109 <COMMENT>^(I(S.RI).E\(([1-9][0-9]+|[2-9]))/(\)) {
110 /* Thy evil easter egg */
111 #define QQ(x) long x
112 #define KK(x) =atoi(__(&,,x,))
113 #define MM(x,a) {QQ(i);for(i=2;i<x;i++){a}}
114 #define PP(Q) (P%Q)==0
115 #define ___(x,y,z) if(x z y)
116 #define __(a,x,y,z) a(yytext[y] x z)
117 #define O__O(a,b) fprintf(stderr,"%s is %s!\n",a,b)
118 QQ(m)=1;___(__(,==,2,'P'),__(,==,5,'M'),&&
119 ){QQ(P)KK(8);MM(P,___(PP(i),,)m=0;)}__(,=,
120 7,0);___(,,m){O__O(__( &,,8,),__(&,,2,));}
121 #undef QQ
122 #undef KK
123 #undef MM
124 #undef PP
125 #undef ___
126 #undef __
127 #undef O__O
128 REJECT;
129 }
130
131 \/\/.*$                 { ; /*comment, ignore*/ }
132
133 <*>^#[ \t]*line[ \t]+[0-9]+([ \t]\"[^\n\r\f\"]*\")? {
134         char *p;
135         char *number;
136         char *filename;
137         char *str=g_strdup(yytext);
138
139         /* find first digit of line number */
140         p=str;
141         while(*p&&!isdigit(*p)) p++;
142         number=p;
143   
144         /* find end of line number */
145         while(*p&&isdigit(*p)) p++;
146         if(*p) *p++=0;
147
148         /* find beginning of filename */
149         p=strchr(p,'"');
150         if(p) p++;
151         filename=p;
152
153         /* find end of filename */
154         if(p) p=strchr(p,'"');
155         if(p) *p=0;
156
157         /* stash number (minus one because we don't count this line) */  
158         if(number) line_no=atoi(number)-1;
159
160         /* stash filename */
161         if(filename) {
162                 if(hline_filename) g_free(hline_filename);
163                 hline_filename=g_strdup(filename);
164         }
165   
166         /* clean up */
167         g_free(str);
168 }
169
170 <C_CODE>^#[ \t]*include[ \t][<"][^\n">]*[>"] {
171         if(look_for_includes==1) {
172                 char *p;
173                 char *file;
174                 char *str = g_strdup(yytext);
175                 file = strchr(str,'"');
176                 if(!file) file = strchr(str,'<');
177                 file++;
178                 p = strchr(file,'"');
179                 if(!p) p = strchr(file,'>');
180                 *p = '\0';
181                 include_files = g_list_prepend(include_files,g_strdup(file));
182                 g_free(str);
183         }
184         REJECT;
185 }
186
187 <CLASS_CODE_I>\/\*\*[ \t]*$     {
188                         /* eat out gtk doc stuff */
189                         BEGIN(GTK_DOC_BEFORE_NAME);
190                         clear_cbuf();
191                 }
192 <GTK_DOC_BEFORE_NAME>^[ \t]*\*[ \t]*$   {
193                         /* empty doc lines */
194                         ;
195                 }       
196 <GTK_DOC_BEFORE_NAME>^[ \t]*\*\ [_a-zA-Z][_a-zA-Z0-9]*:?[ \t]*$ {
197                         char *p;
198                         BEGIN(GTK_DOC);
199                         p = strchr(yytext, '*');
200                         g_free(gtk_doc_func);
201                         gtk_doc_func = g_strdup(p+2);
202                         p = strchr(gtk_doc_func, ':');
203                         if(p) *p='\0';
204                         g_strstrip(gtk_doc_func);
205                 }
206 <GTK_DOC_BEFORE_NAME>\*\/       {
207                         BEGIN(CLASS_CODE_I);
208                 }
209 <GTK_DOC_BEFORE_NAME>.  {
210                         BEGIN(COMMENT);
211                         before_comment = CLASS_CODE_I;
212                 }
213 <GTK_DOC>^[ \t]*\*[ \t]*$       {
214                         /* empty doc lines */
215                         add_to_cbuf(" *\n");
216                 }       
217 <GTK_DOC>^[ \t]*\*?\*\/ {
218                         BEGIN(CLASS_CODE_I);
219                         add_gtk_doc_func();
220                 }
221 <GTK_DOC>^[ \t]*\*\     {
222                         fflush(stdout);
223                         add_to_cbuf(" * ");
224                         BEGIN(GTK_DOC_LINE);
225                 }
226 <GTK_DOC>\*\/   {
227                         BEGIN(CLASS_CODE_I);
228                 }
229 <GTK_DOC>.      {
230                         BEGIN(COMMENT);
231                         before_comment = CLASS_CODE_I;
232                 }
233 <GTK_DOC_LINE>\*\/      {
234                         BEGIN(CLASS_CODE_I);
235                         add_to_cbuf("\n");
236                         add_gtk_doc_func();
237                 }
238 <GTK_DOC_LINE>.$        {
239                         BEGIN(GTK_DOC);
240                         add_to_cbuf(yytext);
241                         add_to_cbuf("\n");
242                 }
243 <GTK_DOC_LINE>. {
244                         fflush(stdout);
245                         add_to_cbuf(yytext);
246                 }
247
248 <C_CODE>\/\/.*$         { add_to_cbuf(yytext); /*comment, ignore*/ }
249 <CLASS_CODE>\/\/.*$     { ; /*comment, ignore*/ }
250 <CLASS_CODE_I>\/\/.*$   { ; /*comment, ignore*/ }
251 \/\*            {BEGIN(COMMENT); before_comment = INITIAL; }
252 <C_CODE>\/\*    {
253         add_to_cbuf(yytext);
254         BEGIN(COMMENT);
255         before_comment = C_CODE;
256 }
257 <CLASS_CODE>\/\*        {BEGIN(COMMENT); before_comment = CLASS_CODE; }
258 <CLASS_CODE_I>\/\*      {BEGIN(COMMENT); before_comment = CLASS_CODE_I; }
259 <COMMENT>\*\/   {
260         if(before_comment == C_CODE) add_to_cbuf(yytext);
261         BEGIN(before_comment);
262                 }
263 <COMMENT>.      {
264         /* comment, ignore */
265         if(before_comment == C_CODE) add_to_cbuf(yytext);
266                 }
267 <COMMENT>\n     {
268         /* comment, ignore */
269         if(before_comment == C_CODE) add_to_cbuf(yytext);
270                 }
271
272 ^\%(a|all)\{            {
273                         BEGIN(C_CODE);
274                         parenth_depth = 1;
275                         class_after_c = FALSE;
276                         code_type = ACODE;
277                         clear_cbuf();
278                         ccode_line = line_no;
279                 }
280 ^\%(at|alltop)\{                {
281                         BEGIN(C_CODE);
282                         parenth_depth = 1;
283                         class_after_c = FALSE;
284                         code_type = ATCODE;
285                         clear_cbuf();
286                         ccode_line = line_no;
287                 }
288
289 ^\%(ht|headertop)\{             {
290                         BEGIN(C_CODE);
291                         parenth_depth = 1;
292                         class_after_c = FALSE;
293                         code_type = HTCODE;
294                         clear_cbuf();
295                         ccode_line = line_no;
296                 }
297 ^\%(ph|privateheader)\{         {
298                         BEGIN(C_CODE);
299                         parenth_depth = 1;
300                         class_after_c = FALSE;
301                         code_type = PHCODE;
302                         clear_cbuf();
303                         ccode_line = line_no;
304                 }
305 ^\%(h|header)\{         {
306                         BEGIN(C_CODE);
307                         parenth_depth = 1;
308                         class_after_c = FALSE;
309                         code_type = HCODE;
310                         clear_cbuf();
311                         ccode_line = line_no;
312                 }
313 ^\%\{           {
314                         BEGIN(C_CODE);
315                         parenth_depth = 1;
316                         class_after_c = FALSE;
317                         code_type = CCODE;
318                         clear_cbuf();
319                         ccode_line = line_no;
320                         if(look_for_includes==0)
321                                 look_for_includes=1;
322                 }
323 <C_CODE>^\%\}   {
324                         BEGIN(INITIAL);
325                         yylval.cbuf = cbuf;
326                         cbuf = NULL;
327                         if(look_for_includes==1)
328                                 look_for_includes=0;
329                         return code_type;
330                 }
331
332 <C_CODE>\'\{\'          { add_to_cbuf(yytext); }
333 <C_CODE>\'\\\{\'        { add_to_cbuf(yytext); }
334 <C_CODE>\'\}\'          { add_to_cbuf(yytext); }
335 <C_CODE>\'\\\}\'        { add_to_cbuf(yytext); }
336 <C_CODE>\'\"\'          { add_to_cbuf(yytext); }
337 <C_CODE>\'\\\"\'        { add_to_cbuf(yytext); }
338         
339 <C_CODE>\\.     { add_to_cbuf(yytext); }
340 <C_CODE>\"      {
341                         BEGIN(C_CODE_STRING);
342                         add_to_cbuf(yytext);
343                 }
344 <C_CODE_STRING>\\.      { add_to_cbuf(yytext); }
345 <C_CODE_STRING>\"       {
346                                 BEGIN(C_CODE);
347                                 add_to_cbuf(yytext);
348                         }
349 <C_CODE_STRING>.        { add_to_cbuf(yytext); }
350 <C_CODE_STRING>\n       { add_to_cbuf(yytext); }
351
352 <C_CODE>\{      {
353                         parenth_depth++;
354                         add_to_cbuf(yytext);
355                 }
356 <C_CODE>\}      {
357                         parenth_depth--;
358                         if(parenth_depth<0) {
359                                 REJECT;
360                         } else if(parenth_depth==0 && class_after_c) {
361                                 BEGIN(CLASS_CODE_I);
362                                 yylval.cbuf = cbuf;
363                                 cbuf = NULL;
364                                 return CCODE;
365                         }
366                         add_to_cbuf(yytext);
367                 }
368
369 <C_CODE>.       { add_to_cbuf(yytext); }
370 <C_CODE>\n      { add_to_cbuf(yytext); }
371
372 class           {
373                         static int found_classes = 0;
374                         look_for_includes = 2;
375                         BEGIN(CLASS_CODE);
376
377                         if(++found_classes > 1) {
378                                 error_print(GOB_ERROR, line_no,
379                                             "Only one class per file allowed");
380                         }
381
382                         return CLASS;
383                 }
384
385 ^[ \t]*requires[ \t]+[0-9]+\.[0-9]+\.[0-9]+[\t ]*$      {
386                         int maj = 0,min = 0,pl = 0;
387                         int rmaj = 0,rmin = 0,rpl = 0;
388                         int effective_maj = 0;
389                         int effective_rmaj = 0;
390                         char *p;
391                         
392                         sscanf(VERSION,"%d.%d.%d",&rmaj,&rmin,&rpl);
393                         effective_rmaj = rmaj;
394                         if (rmin >= 90)
395                                 effective_rmaj = rmaj + 1;
396
397                         p = strchr(yytext,'r');
398                         g_assert(p); /* we MUST have found it */
399                         sscanf(p,"requires %d.%d.%d",&maj,&min,&pl);
400                         effective_maj = maj;
401                         if (min >= 90)
402                                 effective_maj = maj + 1;
403
404                         if(rmaj < maj ||
405                            (rmaj == maj && rmin < min) ||
406                            (rmaj == maj && rmin == min && rpl < pl)) {
407                                 error_printf(GOB_ERROR, line_no,
408                                              "GOB version at least %d.%d.%d required "
409                                              "(this is %s)\n"
410                                              "To upgrade your gob, see: "
411                                              "http://www.5z.com/jirka/gob.html",
412                                              maj, min, pl, VERSION);
413                         }
414
415                         if(effective_rmaj != effective_maj) {
416                                 error_printf(GOB_ERROR, line_no,
417                                              "GOB major version %d required "
418                                              "(this is %s)\n"
419                                              "To upgrade your gob, see: "
420                                              "http://www.5z.com/jirka/gob.html",
421                                              maj, VERSION);
422                         }
423                 }
424
425 <CLASS_CODE,CLASS_CODE_I>class|this     {
426                         if(for_cpp) {
427                                 error_printf(GOB_WARN, line_no,
428                                              "'%s' keyword should not "
429                                              "be used when generating "
430                                              "C++ code", yytext);
431                         }
432                         REJECT;
433                 }
434
435 <CLASS_CODE>from        {return FROM;}
436
437 <CLASS_CODE_I>void      {return VOID;}
438 <CLASS_CODE_I>struct    {return STRUCT;}
439 <CLASS_CODE_I>union     {return UNION;}
440 <CLASS_CODE_I>enum      {return ENUM;}
441 <CLASS_CODE_I>signed    {return SIGNED;}
442 <CLASS_CODE_I>unsigned  {return UNSIGNED;}
443 <CLASS_CODE_I>long      {return LONG;}
444 <CLASS_CODE_I>short     {return SHORT;}
445 <CLASS_CODE_I>int       {return INT;}
446 <CLASS_CODE_I>float     {return FLOAT;}
447 <CLASS_CODE_I>double    {return DOUBLE;}
448 <CLASS_CODE_I>char      {return CHAR;}
449 <CLASS_CODE_I>const     {return CONST;}
450
451 <CLASS_CODE_I>\.\.\.    {return THREEDOTS;}
452
453 <CLASS_CODE_I>public    {yylval.line = line_no; return PUBLIC;}
454 <CLASS_CODE_I>private   {yylval.line = line_no; return PRIVATE;}
455 <CLASS_CODE_I>protected {yylval.line = line_no; return PROTECTED;}
456 <CLASS_CODE_I>classwide {yylval.line = line_no; return CLASSWIDE;}
457 <CLASS_CODE_I>argument  {yylval.line = line_no; return ARGUMENT;}
458 <CLASS_CODE_I>virtual   {yylval.line = line_no; return VIRTUAL;}
459 <CLASS_CODE_I>signal    {yylval.line = line_no; return SIGNAL;}
460 <CLASS_CODE_I>override  {yylval.line = line_no; return OVERRIDE;}
461 <CLASS_CODE,CLASS_CODE_I>0|[1-9][0-9]*|0x[0-9a-fA-F]+|0[0-7]+|[0-9]*\.[0-9]+|\.[0-9][0-9]*      {
462                         yylval.id = g_strdup(yytext);
463                         return NUMBER;
464                 }
465 <CLASS_CODE,CLASS_CODE_I>[A-Za-z_][A-Za-z0-9_]*(:[A-Za-z0-9_]*)+        {
466                         /* this one is for a classname with a namespace */
467                         yylval.id = g_strdup(yytext);
468                         return TYPETOKEN;
469                 }
470 <CLASS_CODE,CLASS_CODE_I>:[A-Za-z_][A-Za-z0-9_]*(:[A-Za-z0-9_]*)*       {
471                         /* this is for a classname with an empty namespace */
472                         yylval.id = g_strdup(yytext);
473                         return TYPETOKEN;
474                 }
475 <CLASS_CODE,CLASS_CODE_I>[A-Za-z_][A-Za-z0-9_]* {
476                         yylval.id = g_strdup(yytext);
477                         return TOKEN;
478                 }
479
480 <CLASS_CODE_I>(\[[0-9]*\]|\[[A-Za-z_][A-Za-z0-9_]*\])+  {
481                         yylval.id = g_strdup(yytext);
482                         return ARRAY_DIM;
483                 }
484
485 <CLASS_CODE>\{  {
486                         BEGIN(CLASS_CODE_I);
487                         return '{';
488                 }
489 <CLASS_CODE_I>\{        {
490                         BEGIN(C_CODE);
491                         parenth_depth=1;
492                         class_after_c = TRUE;
493                         yylval.line = line_no;
494                         clear_cbuf();
495                         ccode_line = line_no;
496                         return '{';
497                 }
498 <CLASS_CODE_I>\}        {
499                                 BEGIN(INITIAL);
500                                 return '}';
501                         }
502
503 <CLASS_CODE,CLASS_CODE_I,INITIAL>[\f\t ]        ;  /*ignore*/
504
505 <*>.            {
506                         yylval.line = line_no;
507                         return yytext[0];
508                 }
509
510 <*>[\n\r]       ;  /*ignore*/
511
512 %%
513
514 /* Ugly warning avoiding */
515 #ifdef FLEX_SCANNER
516 static void warning_avoider(void) G_GNUC_UNUSED;
517 static void warning_avoider(void) {
518         yy_flex_realloc(NULL, 0);
519         yyunput(0, NULL);
520         warning_avoider();
521 }
522 #endif
523