2 * GObject introspection: C lexer
4 * Copyright (c) 1997 Sandro Sigala <ssigala@globalnet.it>
5 * Copyright (c) 2007-2008 Jürg Billeter <j@bitron.ch>
6 * Copyright (c) 2010 Andreas Rottmann <a.rottmann@gmx.at>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 #include "sourcescanner.h"
41 #include "scannerparser.h"
51 #define YY_BUF_SIZE 1048576
53 extern int yylex (GISourceScanner *scanner);
54 #define YY_DECL int yylex (GISourceScanner *scanner)
55 static int yywrap (void);
56 static void parse_comment (GISourceScanner *scanner);
57 static void parse_trigraph (GISourceScanner *scanner);
58 static void process_linemarks (GISourceScanner *scanner);
59 static int check_identifier (GISourceScanner *scanner, const char *);
60 static int parse_ignored_macro (void);
61 static void print_error (GISourceScanner *scanner);
66 intsuffix ([uU][lL]?[lL]?)|([lL][lL]?[uU]?)
67 fracconst ([0-9]*\.[0-9]+)|([0-9]+\.)
68 exppart [eE][-+]?[0-9]+
70 chartext ([^\\\'])|(\\.)
71 stringtext ([^\\\"])|(\\.)
75 \n.* { strncpy(linebuf, yytext+1, sizeof(linebuf)); /* save the next line */
76 linebuf[sizeof(linebuf)-1]='\0';
77 /* printf("%4d:%s\n",lineno,linebuf); */
78 yyless(1); /* give back all but the \n to rescan */
83 [\t\f\v\r ]+ { /* Ignore whitespace. */ }
85 "/*" { parse_comment(scanner); }
86 "/*"[\t ]?<[\t ,=A-Za-z0-9_]+>[\t ]?"*/" { parse_trigraph(scanner); }
87 "//".* { /* Ignore C++ style comments. */ }
89 "#define "[a-zA-Z_][a-zA-Z_0-9]*"(" { yyless (yyleng - 1); return FUNCTION_MACRO; }
90 "#define "[a-zA-Z_][a-zA-Z_0-9]* { return OBJECT_MACRO; }
91 "#ifdef"[\t ]+"__GI_SCANNER__"[\t ]?.*"\n" { return IFDEF_GI_SCANNER; }
92 "#ifndef"[\t ]+"__GI_SCANNER__"[\t ]?.*"\n" { return IFNDEF_GI_SCANNER; }
93 "#ifndef ".*"\n" { return IFNDEF_COND; }
94 "#ifdef ".*"\n" { return IFDEF_COND; }
95 "#if ".*"\n" { return IF_COND; }
96 "#elif ".*"\n" { return ELIF_COND; }
97 "#else".*"\n" { return ELSE_COND; }
98 "#endif".*"\n" { return ENDIF_COND; }
99 "#pragma ".*"\n" { /* Ignore pragma. */ }
101 "# "[0-9]+" ".*"\n" { process_linemarks(scanner); }
115 "..." { return ELLIPSIS; }
131 "+=" { return ADDEQ; }
132 "-=" { return SUBEQ; }
133 "*=" { return MULEQ; }
134 "/=" { return DIVEQ; }
135 "%=" { return MODEQ; }
136 "^=" { return XOREQ; }
137 "&=" { return ANDEQ; }
138 "|=" { return OREQ; }
141 "<<=" { return SLEQ; }
142 ">>=" { return SREQ; }
144 "!=" { return NOTEQ; }
145 "<=" { return LTEQ; }
146 ">=" { return GTEQ; }
147 "&&" { return ANDAND; }
148 "||" { return OROR; }
149 "++" { return PLUSPLUS; }
150 "--" { return MINUSMINUS; }
152 "->" { return ARROW; }
154 "__asm"[\t\f\v\r ]+"volatile" { if (!parse_ignored_macro()) REJECT; }
155 "__asm__"[\t\f\v\r ]+"volatile" { if (!parse_ignored_macro()) REJECT; }
156 "__asm__"[\t\f\v\r ]+"__volatile__" { if (!parse_ignored_macro()) REJECT; }
157 "__asm" { if (!parse_ignored_macro()) REJECT; }
158 "__asm__" { if (!parse_ignored_macro()) REJECT; }
159 "__attribute__" { if (!parse_ignored_macro()) REJECT; }
160 "__attribute" { if (!parse_ignored_macro()) REJECT; }
161 "__const" { return CONST; }
162 "__extension__" { return EXTENSION; }
163 "__inline__" { return INLINE; }
164 "__inline" { return INLINE; }
165 "__nonnull" { if (!parse_ignored_macro()) REJECT; }
166 "_Noreturn" { /* Ignore */ }
167 "__signed__" { return SIGNED; }
168 "__restrict" { return RESTRICT; }
169 "__restrict__" { return RESTRICT; }
170 "__typeof" { if (!parse_ignored_macro()) REJECT; }
171 "__volatile" { return VOLATILE; }
172 "__volatile__" { return VOLATILE; }
173 "_Bool" { return BOOL; }
175 "G_GINT64_CONSTANT" { return INTL_CONST; }
176 "G_GUINT64_CONSTANT" { return INTUL_CONST; }
178 "TRUE" { return BOOLEAN; }
179 "FALSE" { return BOOLEAN; }
180 "true" { return BOOLEAN; }
181 "false" { return BOOLEAN; }
183 [a-zA-Z_][a-zA-Z_0-9]* { if (scanner->macro_scan) return check_identifier(scanner, yytext); else REJECT; }
185 "asm" { if (!parse_ignored_macro()) REJECT; }
186 "auto" { return AUTO; }
187 "break" { return BREAK; }
188 "case" { return CASE; }
189 "char" { return CHAR; }
190 "const" { return CONST; }
191 "continue" { return CONTINUE; }
192 "default" { return DEFAULT; }
194 "double" { return DOUBLE; }
195 "else" { return ELSE; }
196 "enum" { return ENUM; }
197 "extern" { return EXTERN; }
198 "float" { return FLOAT; }
199 "for" { return FOR; }
200 "goto" { return GOTO; }
202 "inline" { return INLINE; }
203 "int" { return INT; }
204 "__uint128_t" { return INT; }
205 "__int128_t" { return INT; }
206 "__uint128" { return INT; }
207 "__int128" { return INT; }
208 "long" { return LONG; }
209 "register" { return REGISTER; }
210 "restrict" { return RESTRICT; }
211 "return" { return RETURN; }
212 "short" { return SHORT; }
213 "signed" { return SIGNED; }
214 "sizeof" { return SIZEOF; }
215 "static" { return STATIC; }
216 "struct" { return STRUCT; }
217 "switch" { return SWITCH; }
218 "typedef" { return TYPEDEF; }
219 "union" { return UNION; }
220 "unsigned" { return UNSIGNED; }
221 "void" { return VOID; }
222 "volatile" { return VOLATILE; }
223 "while" { return WHILE; }
225 [a-zA-Z_][a-zA-Z_0-9]* { return check_identifier(scanner, yytext); }
227 "0"[xX][0-9a-fA-F]+{intsuffix}? { return INTEGER; }
228 "0"[0-7]+{intsuffix}? { return INTEGER; }
229 [0-9]+{intsuffix}? { return INTEGER; }
231 {fracconst}{exppart}?{floatsuffix}? { return FLOATING; }
232 [0-9]+{exppart}{floatsuffix}? { return FLOATING; }
234 "'"{chartext}*"'" { return CHARACTER; }
235 "L'"{chartext}*"'" { return CHARACTER; }
237 "\""{stringtext}*"\"" { return STRING; }
238 "L\""{stringtext}*"\"" { return STRING; }
240 . { print_error(scanner); }
251 parse_comment (GISourceScanner *scanner)
254 GString *string = NULL;
255 GISourceComment *comment;
262 if (c2 != EOF && (c1 == '*' && c2 != '*' && c2 != '/')) {
264 * Store GTK-Doc comment blocks,
265 * starts with one '/' followed by exactly two '*' and not followed by a '/'
267 if (!g_hash_table_contains (scanner->files, scanner->current_file)) {
270 string = g_string_new (yytext);
273 comment_lineno = lineno;
275 while (c2 != EOF && !(c1 == '*' && c2 == '/'))
278 g_string_append_c (string, c1);
291 g_string_append (string, "*/");
293 comment = g_slice_new (GISourceComment);
294 comment->comment = g_string_free (string, FALSE);
295 comment->line = comment_lineno;
296 comment->filename = g_file_get_parse_name (scanner->current_file);
298 gi_source_scanner_take_comment (scanner, comment);
301 * Ignore all other comment blocks
303 while (c2 != EOF && !(c1 == '*' && c2 == '/'))
317 check_identifier (GISourceScanner *scanner,
321 * This function checks if `s' is a type name or an
325 if (gi_source_scanner_is_typedef (scanner, s)) {
327 } else if (strcmp (s, "__builtin_va_list") == 0) {
334 /* taken from glib/gfileutils.c */
335 #if defined(MAXPATHLEN)
336 #define G_PATH_LENGTH MAXPATHLEN
337 #elif defined(PATH_MAX)
338 #define G_PATH_LENGTH PATH_MAX
339 #elif defined(_PC_PATH_MAX)
340 #define G_PATH_LENGTH sysconf(_PC_PATH_MAX)
342 #define G_PATH_LENGTH 2048
346 _realpath (const char *path)
349 char buffer[G_PATH_LENGTH];
351 return realpath (path, buffer) ? g_strdup (buffer) : NULL;
353 /* We don't want to include <windows.h> as it clashes horribly
354 * with token names from scannerparser.h. So just declare
355 * GetFullPathNameA() here unless we already defined it, like
359 extern __stdcall GetFullPathNameA(const char*, int, char*, char**);
365 rc = GetFullPathNameA (path, 1, &dummy, NULL);
368 /* Weird failure, so just return the input path as such */
369 return g_strdup (path);
373 buffer = g_malloc (len);
375 rc = GetFullPathNameA (path, len, buffer, NULL);
376 if (rc == 0 || rc > len)
378 /* Weird failure again */
380 return g_strdup (path);
387 * # linenum "filename" flags
388 * See http://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html
392 process_linemarks (GISourceScanner *scanner)
394 char escaped_filename[1025];
398 sscanf(yytext, "# %d \"%1024[^\"]\"", &lineno, escaped_filename);
399 filename = g_strcompress (escaped_filename);
401 real = _realpath (filename);
408 if (scanner->current_file)
409 g_object_unref (scanner->current_file);
410 scanner->current_file = g_file_new_for_path (filename);
415 * This parses a macro which is ignored, such as
416 * __attribute__((x)) or __asm__ (x)
419 parse_ignored_macro (void)
424 while ((c = input ()) != EOF && isspace (c))
430 while ((c = input ()) != EOF && (nest > 0 || c != ')')) {
436 while ((c = input ()) != EOF && c != '"') {
440 } else if (c == '\'') {
449 } else if (c == '\n')
457 parse_trigraph (GISourceScanner *scanner)
463 start = g_strstr_len (yytext, yyleng, "<");
464 g_assert (start != NULL);
465 end = g_strstr_len (yytext, yyleng, ">");
466 g_assert (end != NULL);
468 items = g_strsplit (start + 1, ",", 0);
469 for (i = 0; items[i] != NULL; i++) {
470 char *item = items[i];
472 if (strcmp (item, "public") == 0)
473 scanner->private = FALSE;
474 else if (strcmp (item, "private") == 0)
475 scanner->private = TRUE;
476 else if (strcmp (item, "flags") == 0)
477 scanner->flags = TRUE;
483 print_error (GISourceScanner *scanner)
486 char *filename = g_file_get_parse_name (scanner->current_file);
487 fprintf(stderr, "%s:%d: unexpected character `%c'\n", filename, lineno, yytext[0]);