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