]> git.draconx.ca Git - gob-dx.git/blob - src/lexer.l
Release 2.0.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 #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 <PROPERTY_CODE_I>\/\/.*$        { ; /*comment, ignore*/ }
264 \/\*            {BEGIN(COMMENT); before_comment = INITIAL; }
265 <C_CODE>\/\*    {
266         add_to_cbuf(yytext);
267         BEGIN(COMMENT);
268         before_comment = C_CODE;
269 }
270 <CLASS_CODE>\/\*        {BEGIN(COMMENT); before_comment = CLASS_CODE; }
271 <CLASS_CODE_I>\/\*      {BEGIN(COMMENT); before_comment = CLASS_CODE_I; }
272 <PROPERTY_CODE_I>\/\*   {BEGIN(COMMENT); before_comment = PROPERTY_CODE_I; }
273 <COMMENT>\*\/   {
274         if(before_comment == C_CODE) add_to_cbuf(yytext);
275         BEGIN(before_comment);
276                 }
277 <COMMENT>.      {
278         /* comment, ignore */
279         if(before_comment == C_CODE) add_to_cbuf(yytext);
280                 }
281 <COMMENT>\n     {
282         /* comment, ignore */
283         if(before_comment == C_CODE) add_to_cbuf(yytext);
284                 }
285
286 ^\%(a|all)\{            {
287                         BEGIN(C_CODE);
288                         parenth_depth = 1;
289                         class_after_c = FALSE;
290                         code_type = ACODE;
291                         clear_cbuf();
292                         ccode_line = line_no;
293                 }
294 ^\%(at|alltop)\{                {
295                         BEGIN(C_CODE);
296                         parenth_depth = 1;
297                         class_after_c = FALSE;
298                         code_type = ATCODE;
299                         clear_cbuf();
300                         ccode_line = line_no;
301                 }
302
303 ^\%(ht|headertop)\{             {
304                         BEGIN(C_CODE);
305                         parenth_depth = 1;
306                         class_after_c = FALSE;
307                         code_type = HTCODE;
308                         clear_cbuf();
309                         ccode_line = line_no;
310                 }
311 ^\%(ph|privateheader)\{         {
312                         BEGIN(C_CODE);
313                         parenth_depth = 1;
314                         class_after_c = FALSE;
315                         code_type = PHCODE;
316                         clear_cbuf();
317                         ccode_line = line_no;
318                 }
319 ^\%(h|header)\{         {
320                         BEGIN(C_CODE);
321                         parenth_depth = 1;
322                         class_after_c = FALSE;
323                         code_type = HCODE;
324                         clear_cbuf();
325                         ccode_line = line_no;
326                 }
327 ^\%\{           {
328                         BEGIN(C_CODE);
329                         parenth_depth = 1;
330                         class_after_c = FALSE;
331                         code_type = CCODE;
332                         clear_cbuf();
333                         ccode_line = line_no;
334                         if(look_for_includes==0)
335                                 look_for_includes=1;
336                 }
337 <C_CODE>^\%\}   {
338                         BEGIN(INITIAL);
339                         yylval.cbuf = cbuf;
340                         cbuf = NULL;
341                         if(look_for_includes==1)
342                                 look_for_includes=0;
343                         return code_type;
344                 }
345
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 <C_CODE>\'\"\'          { add_to_cbuf(yytext); }
351 <C_CODE>\'\\\"\'        { add_to_cbuf(yytext); }
352         
353 <C_CODE>\\.     { add_to_cbuf(yytext); }
354
355
356 <C_CODE>\"      {
357                         BEGIN(CODE_STRING);
358                         before_string = C_CODE;
359                         add_to_cbuf(yytext);
360                 }
361 <PROPERTY_CODE_I>\"     {
362                         BEGIN(CODE_STRING);
363                         before_string = PROPERTY_CODE_I;
364                         add_to_cbuf(yytext);
365                 }
366 <CODE_STRING>\\.        { add_to_cbuf(yytext); }
367 <CODE_STRING>\" {
368                         BEGIN(before_string);
369                         add_to_cbuf(yytext);
370                         if (before_string == PROPERTY_CODE_I) {
371                                 yylval.id = cbuf->str;
372                                 g_string_free (cbuf, FALSE);
373                                 cbuf = NULL;
374                                 return STRING;
375                         }
376                 }
377 <CODE_STRING>.  { add_to_cbuf(yytext); }
378 <CODE_STRING>\n { add_to_cbuf(yytext); }
379
380 <C_CODE>\{      {
381                         parenth_depth++;
382                         add_to_cbuf(yytext);
383                 }
384 <C_CODE>\}      {
385                         parenth_depth--;
386                         if(parenth_depth<0) {
387                                 REJECT;
388                         } else if(parenth_depth==0 && class_after_c) {
389                                 BEGIN(CLASS_CODE_I);
390                                 yylval.cbuf = cbuf;
391                                 cbuf = NULL;
392                                 return CCODE;
393                         }
394                         add_to_cbuf(yytext);
395                 }
396
397 <C_CODE>.       { add_to_cbuf(yytext); }
398 <C_CODE>\n      { add_to_cbuf(yytext); }
399
400 class           {
401                         static int found_classes = 0;
402                         look_for_includes = 2;
403                         BEGIN(CLASS_CODE);
404
405                         if(++found_classes > 1) {
406                                 error_print(GOB_ERROR, line_no,
407                                             "Only one class per file allowed");
408                         }
409
410                         return CLASS;
411                 }
412
413 error           { return ERROR; }
414 enum            { return ENUM; }
415 flags           { return FLAGS; }
416
417 ^[ \t]*requires[ \t]+[0-9]+\.[0-9]+\.[0-9]+[\t ]*$      {
418                         int maj = 0, min = 0, pl = 0;
419                         int rmaj = 0, rmin = 0, rpl = 0;
420                         int effective_maj = 0;
421                         int effective_rmaj = 0;
422                         char *p;
423                         
424                         sscanf (VERSION, "%d.%d.%d", &rmaj, &rmin, &rpl);
425                         effective_rmaj = rmaj;
426                         if (rmin >= 90)
427                                 effective_rmaj = rmaj + 1;
428
429                         p = strchr (yytext,'r');
430                         g_assert (p); /* we MUST have found it */
431                         sscanf (p, "requires %d.%d.%d", &maj, &min, &pl);
432                         effective_maj = maj;
433                         if (min >= 90)
434                                 effective_maj = maj + 1;
435
436                         if(rmaj < maj ||
437                            (rmaj == maj && rmin < min) ||
438                            (rmaj == maj && rmin == min && rpl < pl)) {
439                                 error_printf (GOB_ERROR, line_no,
440                                               "GOB version at least %d.%d.%d required "
441                                               "(this is %s)\n"
442                                               "To upgrade your gob, see: "
443                                               "http://www.5z.com/jirka/gob.html",
444                                               maj, min, pl, VERSION);
445                         }
446
447                         if(effective_rmaj != effective_maj) {
448                                 error_printf(GOB_ERROR, line_no,
449                                              "GOB major version %d required "
450                                              "(this is %s)\n"
451                                              "To upgrade your gob, see: "
452                                              "http://www.5z.com/jirka/gob.html",
453                                              effective_maj, VERSION);
454                         }
455
456                 }
457
458 <CLASS_CODE,CLASS_CODE_I>class|this     {
459                         if(for_cpp) {
460                                 error_printf(GOB_WARN, line_no,
461                                              "'%s' keyword should not "
462                                              "be used when generating "
463                                              "C++ code", yytext);
464                         }
465                         REJECT;
466                 }
467
468 <CLASS_CODE>from        {return FROM;}
469
470 <CLASS_CODE_I,PROPERTY_CODE_I>void      {return VOID;}
471 <CLASS_CODE_I,PROPERTY_CODE_I>struct    {return STRUCT;}
472 <CLASS_CODE_I,PROPERTY_CODE_I>union     {return UNION;}
473 <CLASS_CODE_I,PROPERTY_CODE_I>enum      {return ENUM;}
474 <CLASS_CODE_I,PROPERTY_CODE_I>signed    {return SIGNED;}
475 <CLASS_CODE_I,PROPERTY_CODE_I>unsigned  {return UNSIGNED;}
476 <CLASS_CODE_I,PROPERTY_CODE_I>long      {return LONG;}
477 <CLASS_CODE_I,PROPERTY_CODE_I>short     {return SHORT;}
478 <CLASS_CODE_I,PROPERTY_CODE_I>int       {return INT;}
479 <CLASS_CODE_I,PROPERTY_CODE_I>float     {return FLOAT;}
480 <CLASS_CODE_I,PROPERTY_CODE_I>double    {return DOUBLE;}
481 <CLASS_CODE_I,PROPERTY_CODE_I>char      {return CHAR;}
482 <CLASS_CODE_I,PROPERTY_CODE_I>const     {return CONST;}
483
484 <CLASS_CODE_I>\.\.\.    {return THREEDOTS;}
485
486 <CLASS_CODE_I>public    {yylval.line = line_no; return PUBLIC;}
487 <CLASS_CODE_I>private   {yylval.line = line_no; return PRIVATE;}
488 <CLASS_CODE_I>protected {yylval.line = line_no; return PROTECTED;}
489 <CLASS_CODE_I>classwide {yylval.line = line_no; return CLASSWIDE;}
490 <CLASS_CODE_I>argument  {yylval.line = line_no; return ARGUMENT;}
491 <CLASS_CODE_I>virtual   {yylval.line = line_no; return VIRTUAL;}
492 <CLASS_CODE_I>signal    {yylval.line = line_no; return SIGNAL;}
493 <CLASS_CODE_I>override  {yylval.line = line_no; return OVERRIDE;}
494 <CLASS_CODE_I>property  {
495                                 yylval.line = line_no;
496                                 BEGIN(PROPERTY_CODE);
497                                 return PROPERTY;
498                         }
499 <PROPERTY_CODE_I>nick   { yylval.line = line_no; return NICK; }
500 <PROPERTY_CODE_I>blurb  { yylval.line = line_no; return BLURB; }
501 <PROPERTY_CODE_I>maximum        { yylval.line = line_no; return MAXIMUM; }
502 <PROPERTY_CODE_I>minimum        { yylval.line = line_no; return MINIMUM; }
503 <PROPERTY_CODE_I>default_value  { yylval.line = line_no; return DEFAULT_VALUE; }
504 <PROPERTY_CODE_I>flags  { yylval.line = line_no; return FLAGS; }
505 <PROPERTY_CODE_I>type   { yylval.line = line_no; return TYPE; }
506 <PROPERTY_CODE_I>flags_type     { yylval.line = line_no; return FLAGS_TYPE; }
507 <PROPERTY_CODE_I>enum_type      { yylval.line = line_no; return ENUM_TYPE; }
508 <PROPERTY_CODE_I>param_type     { yylval.line = line_no; return PARAM_TYPE; }
509 <PROPERTY_CODE_I>boxed_type     { yylval.line = line_no; return BOXED_TYPE; }
510 <PROPERTY_CODE_I>object_type    { yylval.line = line_no; return OBJECT_TYPE; }
511 <PROPERTY_CODE>[(]      {
512                 yylval.line = line_no;
513                 property_paren_depth = 1;
514                 BEGIN(PROPERTY_CODE_I);
515                 return '(';
516                         }
517 <PROPERTY_CODE_I>[(]    {
518                 yylval.line = line_no;
519                 property_paren_depth++;
520                 return '(';
521                         }
522 <PROPERTY_CODE_I>[)]    {
523                 yylval.line = line_no;
524                 property_paren_depth--;
525                 if (property_paren_depth == 0) {
526                         BEGIN(CLASS_CODE_I);
527                 }
528                 return ')';
529                         }
530
531 <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]*        {
532                         yylval.id = g_strdup(yytext);
533                         return NUMBER;
534                 }
535 <CLASS_CODE,CLASS_CODE_I,PROPERTY_CODE,PROPERTY_CODE_I,INITIAL>[A-Za-z_][A-Za-z0-9_]*(:[A-Za-z0-9_]*)+  {
536                         /* this one is for a classname with a namespace */
537                         yylval.id = g_strdup(yytext);
538                         return TYPETOKEN;
539                 }
540 <CLASS_CODE,CLASS_CODE_I,PROPERTY_CODE,PROPERTY_CODE_I,INITIAL>:[A-Za-z_][A-Za-z0-9_]*(:[A-Za-z0-9_]*)* {
541                         /* this is for a classname with an empty namespace */
542                         yylval.id = g_strdup(yytext);
543                         return TYPETOKEN;
544                 }
545 <CLASS_CODE,CLASS_CODE_I,PROPERTY_CODE,PROPERTY_CODE_I,INITIAL>[A-Za-z_][A-Za-z0-9_]*   {
546                         yylval.id = g_strdup(yytext);
547                         return TOKEN;
548                 }
549 <CLASS_CODE,CLASS_CODE_I,PROPERTY_CODE,PROPERTY_CODE_I,INITIAL>\'\\.\'|\'.\'    {
550                         yylval.id = g_strdup(yytext);
551                         return SINGLE_CHAR;
552                 }
553
554 <CLASS_CODE_I>(\[[0-9]*\]|\[[A-Za-z_][A-Za-z0-9_]*\])+  {
555                         yylval.id = g_strdup(yytext);
556                         return ARRAY_DIM;
557                 }
558
559 <CLASS_CODE>\{  {
560                         BEGIN(CLASS_CODE_I);
561                         return '{';
562                 }
563 <CLASS_CODE_I>\{        {
564                         BEGIN(C_CODE);
565                         parenth_depth=1;
566                         class_after_c = TRUE;
567                         yylval.line = line_no;
568                         clear_cbuf();
569                         ccode_line = line_no;
570                         return '{';
571                 }
572 <CLASS_CODE_I>\}        {
573                                 BEGIN(INITIAL);
574                                 return '}';
575                         }
576
577 <CLASS_CODE,CLASS_CODE_I,INITIAL,PROPERTY_CODE,PROPERTY_CODE_I>[\f\t ]  ;  /*ignore*/
578
579 <*>.            {
580                         yylval.line = line_no;
581                         return yytext[0];
582                 }
583
584 <*>[\n\r]       ;  /*ignore*/
585
586 %%
587
588 /* Ugly warning avoiding */
589 #ifdef FLEX_SCANNER
590 static void warning_avoider(void) G_GNUC_UNUSED;
591 static void warning_avoider(void) {
592         yy_flex_realloc(NULL, 0);
593         yyunput(0, NULL);
594         warning_avoider();
595 }
596 #endif
597