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