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