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>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "sourcescanner.h"
36 #include "scannerparser.h"
37 #include "grealpath.h"
42 #define YY_BUF_SIZE 65536
44 extern int yylex (GISourceScanner *scanner);
45 #define YY_DECL int yylex (GISourceScanner *scanner)
46 static int yywrap (void);
47 static void parse_comment (GISourceScanner *scanner);
48 static void process_directive (GISourceScanner *scanner);
49 static int check_identifier (GISourceScanner *scanner, const char *);
50 static int parse_ignored_macro (void);
53 intsuffix ([uU][lL]?[lL]?)|([lL][lL]?[uU]?)
54 fracconst ([0-9]*\.[0-9]+)|([0-9]+\.)
55 exppart [eE][-+]?[0-9]+
57 chartext ([^\\\'])|(\\.)
58 stringtext ([^\\\"])|(\\.)
62 "\n" { ++lineno; } /* " */
64 [\t\f\v\r ]+ { /* Ignore whitespace. */ }
66 "/*" { parse_comment(scanner); }
69 "#define "[a-zA-Z_][a-zA-Z_0-9]*"(" { yyless (yyleng - 1); return FUNCTION_MACRO; }
70 "#define "[a-zA-Z_][a-zA-Z_0-9]* { return OBJECT_MACRO; }
72 "#" { process_directive(scanner); }
86 "..." { return ELLIPSIS; }
102 "+=" { return ADDEQ; }
103 "-=" { return SUBEQ; }
104 "*=" { return MULEQ; }
105 "/=" { return DIVEQ; }
106 "%=" { return MODEQ; }
107 "^=" { return XOREQ; }
108 "&=" { return ANDEQ; }
109 "|=" { return OREQ; }
112 "<<=" { return SLEQ; }
113 ">>=" { return SREQ; }
115 "!=" { return NOTEQ; }
116 "<=" { return LTEQ; }
117 ">=" { return GTEQ; }
118 "&&" { return ANDAND; }
119 "||" { return OROR; }
120 "++" { return PLUSPLUS; }
121 "--" { return MINUSMINUS; }
123 "->" { return ARROW; }
125 "__asm" { if (!parse_ignored_macro()) REJECT; }
126 "__asm__" { if (!parse_ignored_macro()) REJECT; }
127 "__attribute__" { if (!parse_ignored_macro()) REJECT; }
128 "__attribute" { if (!parse_ignored_macro()) REJECT; }
129 "__const" { return CONST; }
130 "__extension__" { return EXTENSION; }
131 "__inline" { return INLINE; }
132 "__nonnull" { if (!parse_ignored_macro()) REJECT; }
133 "__signed__" { return SIGNED; }
134 "__restrict" { return RESTRICT; }
135 "__typeof" { if (!parse_ignored_macro()) REJECT; }
136 "_Bool" { return BOOL; }
138 [a-zA-Z_][a-zA-Z_0-9]* { if (scanner->macro_scan) return IDENTIFIER; else REJECT; }
140 "asm" { if (!parse_ignored_macro()) REJECT; }
141 "auto" { return AUTO; }
142 "break" { return BREAK; }
143 "case" { return CASE; }
144 "char" { return CHAR; }
145 "const" { return CONST; }
146 "continue" { return CONTINUE; }
147 "default" { return DEFAULT; }
149 "double" { return DOUBLE; }
150 "else" { return ELSE; }
151 "enum" { return ENUM; }
152 "extern" { return EXTERN; }
153 "float" { return FLOAT; }
154 "for" { return FOR; }
155 "goto" { return GOTO; }
157 "inline" { return INLINE; }
158 "int" { return INT; }
159 "long" { return LONG; }
160 "register" { return REGISTER; }
161 "restrict" { return RESTRICT; }
162 "return" { return RETURN; }
163 "short" { return SHORT; }
164 "signed" { return SIGNED; }
165 "sizeof" { return SIZEOF; }
166 "static" { return STATIC; }
167 "struct" { return STRUCT; }
168 "switch" { return SWITCH; }
169 "typedef" { return TYPEDEF; }
170 "union" { return UNION; }
171 "unsigned" { return UNSIGNED; }
172 "void" { return VOID; }
173 "volatile" { return VOLATILE; }
174 "while" { return WHILE; }
176 [a-zA-Z_][a-zA-Z_0-9]* { return check_identifier(scanner, yytext); }
178 "0"[xX][0-9a-fA-F]+{intsuffix}? { return INTEGER; }
179 "0"[0-7]+{intsuffix}? { return INTEGER; }
180 [0-9]+{intsuffix}? { return INTEGER; }
182 {fracconst}{exppart}?{floatsuffix}? { return FLOATING; }
183 [0-9]+{exppart}{floatsuffix}? { return FLOATING; }
185 "'"{chartext}*"'" { return CHARACTER; }
186 "L'"{chartext}*"'" { return CHARACTER; }
188 "\""{stringtext}*"\"" { return STRING; }
189 "L\""{stringtext}*"\"" { return STRING; }
191 . { fprintf(stderr, "%s:%d: unexpected character `%c'\n", scanner->current_filename, lineno, yytext[0]); }
203 parse_gtkdoc (GISourceScanner *scanner,
208 gboolean isline = FALSE;
212 GISourceDirective *directive;
215 GSList *options = NULL;
219 line_buf = g_string_new ("");
229 g_string_append_c (line_buf, *c1);
231 } while (*c2 != EOF && !(*c1 == '*' && *c2 == '/'));
235 g_string_free (line_buf, TRUE);
239 line = g_string_free (line_buf, FALSE);
241 /* Ignore lines that don't have a : - this is a hack but avoids
242 * trying to parse too many things as annotations
244 if (!strchr (line, ':'))
250 parts = g_strsplit (line, ":", 3);
251 n_parts = g_strv_length (parts);
253 if (g_ascii_strcasecmp (parts[0], "eprecated") == 0)
256 options = g_slist_prepend (options, g_strdup_printf ("%s: %s", parts[1], parts[2]));
257 else if (n_parts == 2)
258 options = g_slist_prepend (options, g_strdup (parts[1]));
260 options = g_slist_prepend (options, g_strdup (""));
264 else if (g_ascii_strcasecmp (parts[0], "ince") == 0)
267 options = g_slist_prepend (options, g_strdup (parts[1]));
269 options = g_slist_prepend (options, g_strdup (""));
273 else if (n_parts >= 2)
279 char *ptr = g_strdup (parts[1]);
284 start = strchr (ptr, '(');
285 while (start != NULL)
287 end = strchr (start, ')');
290 options = g_slist_prepend (options, g_strndup (start+1, end-(start+1)));
291 start = strchr (end+1, '(');
304 else /* parts == 1 */
311 * Special cases for global annotations.
312 * Context-sensitive parsing would probably be the right way to go.
314 if (g_ascii_strncasecmp ("eturn", name, 5) == 0)
316 else if (g_ascii_strncasecmp ("eprecated", name, 9) == 0)
317 rname = "deprecated";
318 else if (g_ascii_strncasecmp ("ince", name, 4) == 0)
323 directive = gi_source_directive_new (rname, value, options);
324 directives = g_hash_table_lookup (scanner->directives_map, symbol);
325 directives = g_slist_prepend (directives, directive);
326 g_hash_table_replace (scanner->directives_map,
327 g_strdup (symbol), directives);
335 parse_comment (GISourceScanner *scanner)
337 GString *symbol = NULL;
338 gboolean startofline = FALSE, have_symbol = FALSE, start1 = FALSE, start_symbol = FALSE;
344 while (c2 != EOF && !(c1 == '*' && c2 == '/'))
350 else if (c1 == '*' && start1)
352 else if (!have_symbol && start_symbol)
355 symbol = g_string_new ("");
357 g_string_append_c (symbol, c1);
369 if ((c1 != '*' && c1 != ' '))
372 if (startofline && (c1 == ' ') && ((c2 == '@') || (c2 == 'r') || (c2 == 'R') || (c2 == 'D') || (c2 == 'S')))
377 parse_gtkdoc (scanner, symbol->str, &c1, &c2);
382 g_string_free (symbol, TRUE);
387 check_identifier (GISourceScanner *scanner,
391 * This function checks if `s' is a type name or an
395 if (gi_source_scanner_is_typedef (scanner, s)) {
397 } else if (strcmp (s, "__builtin_va_list") == 0) {
405 process_directive (GISourceScanner *scanner)
407 /* extract current filename from #line directives */
408 GString *filename_builder;
409 gboolean in_string, found_filename;
412 found_filename = FALSE;
414 filename_builder = g_string_new ("");
417 while (c != EOF && c != '\n') {
421 found_filename = TRUE;
422 } else if (c >= '0' && c <= '9') {
423 if (!found_filename) {
424 lineno = lineno * 10 + (c - '0');
430 } else if (c == '\\') {
431 g_string_append_c (filename_builder, c);
433 g_string_append_c (filename_builder, c);
435 g_string_append_c (filename_builder, c);
441 if (filename_builder->len > 0) {
442 char *filename = g_strcompress (filename_builder->str);
443 if (g_realpath (filename))
445 g_free (scanner->current_filename);
446 scanner->current_filename = g_realpath (filename);
447 g_assert (scanner->current_filename);
452 g_string_free (filename_builder, TRUE);
456 * This parses a macro which is ignored, such as
457 * __attribute__((x)) or __asm__ (x)
460 parse_ignored_macro (void)
465 while ((c = input ()) != EOF && isspace (c))
471 while ((c = input ()) != EOF && (nest > 0 || c != ')')) {
477 while ((c = input ()) != EOF && c != '"') {
481 } else if (c == '\'') {
490 } else if (c == '\n')