]> git.draconx.ca Git - gob-dx.git/blob - src/lexer.l
68bafd020eba981874ce6b990a026989742eb1cd
[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 ^\%(ht|headertop)\{             {
205                         BEGIN(C_CODE);
206                         parenth_depth = 1;
207                         class_after_c = FALSE;
208                         code_type = HTCODE;
209                         clear_cbuf();
210                         ccode_line = line_no;
211                 }
212 ^\%(ph|privateheader)\{         {
213                         BEGIN(C_CODE);
214                         parenth_depth = 1;
215                         class_after_c = FALSE;
216                         code_type = PHCODE;
217                         clear_cbuf();
218                         ccode_line = line_no;
219                 }
220 ^\%(h|header)\{         {
221                         BEGIN(C_CODE);
222                         parenth_depth = 1;
223                         class_after_c = FALSE;
224                         code_type = HCODE;
225                         clear_cbuf();
226                         ccode_line = line_no;
227                 }
228 ^\%\{           {
229                         BEGIN(C_CODE);
230                         parenth_depth = 1;
231                         class_after_c = FALSE;
232                         code_type = CCODE;
233                         clear_cbuf();
234                         ccode_line = line_no;
235                         if(look_for_includes==0)
236                                 look_for_includes=1;
237                 }
238 <C_CODE>^\%\}   {
239                         BEGIN(INITIAL);
240                         yylval.cbuf = cbuf;
241                         cbuf = NULL;
242                         if(look_for_includes==1)
243                                 look_for_includes=0;
244                         return code_type;
245                 }
246
247 <C_CODE>\'\{\'          { add_to_cbuf(yytext); }
248 <C_CODE>\'\\\{\'        { add_to_cbuf(yytext); }
249 <C_CODE>\'\}\'          { add_to_cbuf(yytext); }
250 <C_CODE>\'\\\}\'        { add_to_cbuf(yytext); }
251 <C_CODE>\'\"\'          { add_to_cbuf(yytext); }
252 <C_CODE>\'\\\"\'        { add_to_cbuf(yytext); }
253         
254 <C_CODE>\\.     { add_to_cbuf(yytext); }
255 <C_CODE>\"      {
256                         BEGIN(C_CODE_STRING);
257                         add_to_cbuf(yytext);
258                 }
259 <C_CODE_STRING>\\.      { add_to_cbuf(yytext); }
260 <C_CODE_STRING>\"       {
261                                 BEGIN(C_CODE);
262                                 add_to_cbuf(yytext);
263                         }
264 <C_CODE_STRING>.        { add_to_cbuf(yytext); }
265 <C_CODE_STRING>\n       { add_to_cbuf(yytext); }
266
267 <C_CODE>\{      {
268                         parenth_depth++;
269                         add_to_cbuf(yytext);
270                 }
271 <C_CODE>\}      {
272                         parenth_depth--;
273                         if(parenth_depth<0) {
274                                 REJECT;
275                         } else if(parenth_depth==0 && class_after_c) {
276                                 BEGIN(CLASS_CODE_I);
277                                 yylval.cbuf = cbuf;
278                                 cbuf = NULL;
279                                 return CCODE;
280                         }
281                         add_to_cbuf(yytext);
282                 }
283
284 <C_CODE>.       { add_to_cbuf(yytext); }
285 <C_CODE>\n      { add_to_cbuf(yytext); }
286
287 class           {
288                         static int found_classes = 0;
289                         look_for_includes = 2;
290                         BEGIN(CLASS_CODE);
291
292                         if(++found_classes > 1) {
293                                 print_error(FALSE, 
294                                             "Only one class per file allowed",
295                                             line_no);
296                         }
297
298                         return CLASS;
299                 }
300
301 ^[ \t]*requires[ \t]+[0-9]+\.[0-9]+\.[0-9]+[\t ]*$      {
302                         int maj = 0,min = 0,pl = 0;
303                         int rmaj = 0,rmin = 0,rpl = 0;
304                         char *p;
305                         
306                         sscanf(VERSION,"%d.%d.%d",&rmaj,&rmin,&rpl);
307                         p = strchr(yytext,'r');
308                         g_assert(p); /* we MUST have found it */
309                         sscanf(p,"requires %d.%d.%d",&maj,&min,&pl);
310                         if(rmaj < maj ||
311                            (rmaj == maj && rmin < min) ||
312                            (rmaj == maj && rmin == min && rpl < pl)) {
313                                 char *s;
314                                 s = g_strdup_printf(
315                                     "GOB version %d.%d.%d required "
316                                     "(this is %s)\n"
317                                     "To upgrade your gob, see: "
318                                     "http://www.5z.com/jirka/gob.html",
319                                     maj,min,pl,VERSION);
320                                 print_error(FALSE, s, line_no);
321                                 g_free(s);
322                         }
323                 }
324
325 <CLASS_CODE,CLASS_CODE_I>class|this     {
326                         if(for_cpp) {
327                                 char *s;
328                                 s = g_strdup_printf("'%s' keyword should not "
329                                                     "be used when generating "
330                                                     "C++ code",yytext);
331                                 print_error(TRUE, s, line_no);
332                                 g_free(s);
333                         }
334                         REJECT;
335                 }
336
337 <CLASS_CODE>from        {return FROM;}
338
339 <CLASS_CODE_I>void      {return VOID;}
340 <CLASS_CODE_I>struct    {return STRUCT;}
341 <CLASS_CODE_I>union     {return UNION;}
342 <CLASS_CODE_I>enum      {return ENUM;}
343 <CLASS_CODE_I>signed    {return SIGNED;}
344 <CLASS_CODE_I>unsigned  {return UNSIGNED;}
345 <CLASS_CODE_I>long      {return LONG;}
346 <CLASS_CODE_I>short     {return SHORT;}
347 <CLASS_CODE_I>int       {return INT;}
348 <CLASS_CODE_I>float     {return FLOAT;}
349 <CLASS_CODE_I>double    {return DOUBLE;}
350 <CLASS_CODE_I>char      {return CHAR;}
351 <CLASS_CODE_I>const     {return CONST;}
352
353 <CLASS_CODE_I>\.\.\.    {return THREEDOTS;}
354
355 <CLASS_CODE_I>public    {yylval.line = line_no; return PUBLIC;}
356 <CLASS_CODE_I>private   {yylval.line = line_no; return PRIVATE;}
357 <CLASS_CODE_I>protected {yylval.line = line_no; return PROTECTED;}
358 <CLASS_CODE_I>argument  {yylval.line = line_no; return ARGUMENT;}
359 <CLASS_CODE_I>virtual   {yylval.line = line_no; return VIRTUAL;}
360 <CLASS_CODE_I>signal    {yylval.line = line_no; return SIGNAL;}
361 <CLASS_CODE_I>override  {yylval.line = line_no; return OVERRIDE;}
362 <CLASS_CODE_I>onerror   {return ONERROR;}
363 <CLASS_CODE_I>0|[1-9][0-9]*|0x[0-9a-fA-F]+|0[0-7]+|[0-9]*\.[0-9]+|\.[0-9][0-9]* {
364                         yylval.id = g_strdup(yytext);
365                         return NUMBER;
366                 }
367 <CLASS_CODE,CLASS_CODE_I>:?[A-Za-z_][A-Za-z0-9_]*(:[A-Za-z0-9_]*)+      {
368                         yylval.id = g_strdup(yytext);
369                         return TYPETOKEN;
370                 }
371 <CLASS_CODE,CLASS_CODE_I>[A-Za-z_][A-Za-z0-9_]* {
372                         yylval.id = g_strdup(yytext);
373                         return TOKEN;
374                 }
375
376 <CLASS_CODE_I>(\[[0-9]*\])+     {
377                         yylval.id = g_strdup(yytext);
378                         return ARRAY_DIM;
379                 }
380
381 <CLASS_CODE>\{  {
382                         BEGIN(CLASS_CODE_I);
383                         return '{';
384                 }
385 <CLASS_CODE_I>\{        {
386                         BEGIN(C_CODE);
387                         parenth_depth=1;
388                         class_after_c = TRUE;
389                         yylval.line = line_no;
390                         clear_cbuf();
391                         ccode_line = line_no;
392                         return '{';
393                 }
394 <CLASS_CODE_I>\}        {
395                                 BEGIN(INITIAL);
396                                 return '}';
397                         }
398
399 <CLASS_CODE,CLASS_CODE_I,INITIAL>[\t ]  ;  /*ignore*/
400
401 <*>.            {
402                         yylval.line = line_no;
403                         return yytext[0];
404                 }
405
406 <*>[\n\r]       ;  /*ignore*/