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