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