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