summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Dahlin <johan@gnome.org>2008-03-25 20:53:32 +0000
committerJohan Dahlin <johan@src.gnome.org>2008-03-25 20:53:32 +0000
commit66ab1202b6499e030c32c9d0d3432e0b09bee7db (patch)
treead2a54a99ea71cf5c42afd03810a761f09096fb8
parent07d433428ed39ef43d0204cb44a75cb31d38016a (diff)
downloadgobject-introspection-66ab1202b6499e030c32c9d0d3432e0b09bee7db.tar.gz
Move the scanner to a separate library.
2008-03-25 Johan Dahlin <johan@gnome.org> * Makefile.am: * configure.ac: * giscanner/Makefile.am: * giscanner/sourcescanner.c: * giscanner/sourcescanner.h: * tools/Makefile.am: * tools/grealpath.h: * tools/sourcescanner.c: * tools/sourcescanner.h: Move the scanner to a separate library. svn path=/trunk/; revision=164
-rw-r--r--ChangeLog14
-rw-r--r--Makefile.am2
-rw-r--r--configure.ac1
-rw-r--r--giscanner/Makefile.am25
-rw-r--r--giscanner/grealpath.h (renamed from tools/grealpath.h)0
-rw-r--r--giscanner/scannerlexer.l394
-rw-r--r--giscanner/scannerparser.y1268
-rw-r--r--giscanner/sourcescanner.c (renamed from tools/sourcescanner.c)7
-rw-r--r--giscanner/sourcescanner.h (renamed from tools/sourcescanner.h)6
-rw-r--r--tools/Makefile.am36
10 files changed, 1731 insertions, 22 deletions
diff --git a/ChangeLog b/ChangeLog
index ef0f824f..20be8f6d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2008-03-25 Johan Dahlin <johan@gnome.org>
+
+ * Makefile.am:
+ * configure.ac:
+ * giscanner/Makefile.am:
+ * giscanner/sourcescanner.c:
+ * giscanner/sourcescanner.h:
+ * tools/Makefile.am:
+ * tools/grealpath.h:
+ * tools/sourcescanner.c:
+ * tools/sourcescanner.h:
+
+ Move the scanner to a separate library.
+
2008-03-23 Johan Dahlin <johan@gnome.org>
* tools/Makefile.am:
diff --git a/Makefile.am b/Makefile.am
index 189f1d72..32d16280 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
## Process this file with automake to produce Makefile.in
ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = gidl girepository tools tests
+SUBDIRS = gidl girepository giscanner tools tests
DIST_SUBDIRS = m4 $(SUBDIRS)
pkgconfigdir = $(libdir)/pkgconfig
diff --git a/configure.ac b/configure.ac
index 00cbc3c4..5ca163df 100644
--- a/configure.ac
+++ b/configure.ac
@@ -94,6 +94,7 @@ AC_CHECK_FUNCS([memchr strchr strspn strstr strtol strtoull])
AC_CONFIG_FILES([Makefile
gidl/Makefile
girepository/Makefile
+ giscanner/Makefile
m4/Makefile
tools/Makefile
tests/Makefile
diff --git a/giscanner/Makefile.am b/giscanner/Makefile.am
new file mode 100644
index 00000000..30ed3352
--- /dev/null
+++ b/giscanner/Makefile.am
@@ -0,0 +1,25 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -I$(top_srcdir)/girepository
+BUILT_SOURCES = scannerparser.c scannerparser.h scannerlexer.c scannerlexer.h
+
+CLEANFILES = scannerparser.c scannerparser.h scannerlexer.c scannerlexer.h
+AM_YFLAGS = -d -t
+
+# Why do I have to do this automake?
+scannerlexer.h: scannerlexer.c
+
+noinst_LTLIBRARIES = libgiscanner.la
+
+libgiscanner_la_SOURCES = \
+ sourcescanner.c \
+ sourcescanner.h \
+ scannerlexer.l \
+ scannerparser.y \
+ grealpath.h
+libgiscanner_la_LIBADD = $(GOBJECT_LIBS)
+libgiscanner_la_CFLAGS = $(GOBJECT_CFLAGS)
+
+GCOVSOURCES = $(libgiscanner_la_SOURCES)
+
+include $(top_srcdir)/gcov.mak
diff --git a/tools/grealpath.h b/giscanner/grealpath.h
index ca88190b..ca88190b 100644
--- a/tools/grealpath.h
+++ b/giscanner/grealpath.h
diff --git a/giscanner/scannerlexer.l b/giscanner/scannerlexer.l
new file mode 100644
index 00000000..03455d73
--- /dev/null
+++ b/giscanner/scannerlexer.l
@@ -0,0 +1,394 @@
+/* -*- Mode: C -*-
+/* GObject introspection: C lexer
+ *
+ * Copyright (c) 1997 Sandro Sigala <ssigala@globalnet.it>
+ * Copyright (c) 2007-2008 Jürg Billeter <j@bitron.ch>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+#include <ctype.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include "sourcescanner.h"
+#include "scannerparser.h"
+#include "grealpath.h"
+
+int lineno;
+
+extern int yylex (GISourceScanner *scanner);
+#define YY_DECL int yylex (GISourceScanner *scanner)
+static int yywrap (void);
+static void parse_comment (GISourceScanner *scanner);
+static void process_directive (GISourceScanner *scanner);
+static int check_identifier (GISourceScanner *scanner, const char *);
+%}
+
+intsuffix ([uU][lL]?)|([lL][uU]?)
+fracconst ([0-9]*\.[0-9]+)|([0-9]+\.)
+exppart [eE][-+]?[0-9]+
+floatsuffix [fFlL]
+chartext ([^\'])|(\\.)
+stringtext ([^\"])|(\\.)
+
+%%
+
+"\n" { ++lineno; } /* " */
+[\t\f\v\r ]+ { /* Ignore whitespace. */ }
+
+"/*" { parse_comment(scanner); }
+"//".* { }
+
+"#define "[a-zA-Z_][a-zA-Z_0-9]*"(" { yyless (yyleng - 1); return FUNCTION_MACRO; }
+"#define "[a-zA-Z_][a-zA-Z_0-9]* { return OBJECT_MACRO; }
+
+"#" { process_directive(scanner); }
+
+"{" { return '{'; }
+"<%" { return '{'; }
+"}" { return '}'; }
+"%>" { return '}'; }
+"[" { return '['; }
+"<:" { return '['; }
+"]" { return ']'; }
+":>" { return ']'; }
+"(" { return '('; }
+")" { return ')'; }
+";" { return ';'; }
+":" { return ':'; }
+"..." { return ELLIPSIS; }
+"?" { return '?'; }
+"." { return '.'; }
+"+" { return '+'; }
+"-" { return '-'; }
+"*" { return '*'; }
+"/" { return '/'; }
+"%" { return '%'; }
+"^" { return '^'; }
+"&" { return '&'; }
+"|" { return '|'; }
+"~" { return '~'; }
+"!" { return '!'; }
+"=" { return '='; }
+"<" { return '<'; }
+">" { return '>'; }
+"+=" { return ADDEQ; }
+"-=" { return SUBEQ; }
+"*=" { return MULEQ; }
+"/=" { return DIVEQ; }
+"%=" { return MODEQ; }
+"^=" { return XOREQ; }
+"&=" { return ANDEQ; }
+"|=" { return OREQ; }
+"<<" { return SL; }
+">>" { return SR; }
+"<<=" { return SLEQ; }
+">>=" { return SREQ; }
+"==" { return EQ; }
+"!=" { return NOTEQ; }
+"<=" { return LTEQ; }
+">=" { return GTEQ; }
+"&&" { return ANDAND; }
+"||" { return OROR; }
+"++" { return PLUSPLUS; }
+"--" { return MINUSMINUS; }
+"," { return ','; }
+"->" { return ARROW; }
+
+[a-zA-Z_][a-zA-Z_0-9]* { if (scanner->macro_scan) return IDENTIFIER; else REJECT; }
+
+"auto" { return AUTO; }
+"_Bool" { return BOOL; }
+"break" { return BREAK; }
+"case" { return CASE; }
+"char" { return CHAR; }
+"const" { return CONST; }
+"continue" { return CONTINUE; }
+"default" { return DEFAULT; }
+"do" { return DO; }
+"double" { return DOUBLE; }
+"else" { return ELSE; }
+"enum" { return ENUM; }
+"extern" { return EXTERN; }
+"float" { return FLOAT; }
+"for" { return FOR; }
+"goto" { return GOTO; }
+"if" { return IF; }
+"inline" { return INLINE; }
+"int" { return INT; }
+"long" { return LONG; }
+"register" { return REGISTER; }
+"restrict" { return RESTRICT; }
+"return" { return RETURN; }
+"short" { return SHORT; }
+"signed" { return SIGNED; }
+"sizeof" { return SIZEOF; }
+"static" { return STATIC; }
+"struct" { return STRUCT; }
+"switch" { return SWITCH; }
+"typedef" { return TYPEDEF; }
+"union" { return UNION; }
+"unsigned" { return UNSIGNED; }
+"void" { return VOID; }
+"volatile" { return VOLATILE; }
+"while" { return WHILE; }
+
+[a-zA-Z_][a-zA-Z_0-9]* { return check_identifier(scanner, yytext); }
+
+"0"[xX][0-9a-fA-F]+{intsuffix}? { return INTEGER; }
+"0"[0-7]+{intsuffix}? { return INTEGER; }
+[0-9]+{intsuffix}? { return INTEGER; }
+
+{fracconst}{exppart}?{floatsuffix}? { return FLOATING; }
+[0-9]+{exppart}{floatsuffix}? { return FLOATING; }
+
+"'"{chartext}*"'" { return CHARACTER; }
+"L'"{chartext}*"'" { return CHARACTER; }
+
+"\""{stringtext}*"\"" { return STRING; }
+"L\""{stringtext}*"\"" { return STRING; }
+
+. { fprintf(stderr, "%s:%d: unexpected character `%c'\n", scanner->current_filename, lineno, yytext[0]); }
+
+%%
+
+static int
+yywrap (void)
+{
+ return 1;
+}
+
+
+static void
+parse_gtkdoc (GISourceScanner *scanner,
+ gchar *symbol,
+ int *c1,
+ int *c2)
+{
+ gboolean isline = FALSE;
+ gchar line[256];
+ int i;
+ gchar **parts;
+ GISourceDirective *directive;
+ char *name,*value;
+ GSList *directives;
+ GSList *options = NULL;
+ char *rname;
+
+ i = 0;
+ do
+ {
+ *c1 = *c2;
+ if (*c1 == '\n')
+ {
+ isline = TRUE;
+ break;
+ }
+ if (i >= 256)
+ break;
+ line[i++] = *c1;
+ *c2 = input();
+ } while (*c2 != EOF && !(*c1 == '*' && *c2 == '/'));
+
+ if (!isline)
+ return;
+
+ line[i] = '\0';
+
+ parts = g_strsplit (line, ": ", 3);
+
+ if (g_strv_length (parts) >= 2)
+ {
+ name = parts[0];
+
+ if (g_strv_length (parts) == 3)
+ {
+ char *ptr = parts[1];
+ GString *current = NULL;
+ gboolean open = (*ptr == '(');
+
+ current = g_string_new ("");
+ value = parts[2];
+
+ while (*ptr++)
+ {
+ if (*ptr == '(')
+ open = TRUE;
+ else if (*ptr != ')' && open)
+ g_string_append_c (current, *ptr);
+ else if (*ptr == ')') {
+ options = g_slist_prepend (options, g_strdup (current->str));
+ open = FALSE;
+ }
+ }
+ g_string_free (current, TRUE);
+ }
+ else
+ value = parts[1];
+ }
+ else /* parts == 1 */
+ {
+ name = parts[0];
+ value = NULL;
+ }
+
+ /*
+ * This is a special case for return values, name will only be
+ * 'eturn' or a valid name, check the call site.
+ * Context-sensitive parsing would probably be the right way to go
+ */
+ if (g_ascii_strncasecmp ("eturn", name, 5) == 0)
+ rname = "return";
+ else
+ rname = name;
+
+ directive = gi_source_directive_new (rname, value, options);
+ directives = g_hash_table_lookup (scanner->directives_map, symbol);
+ directives = g_slist_prepend (directives, directive);
+ g_hash_table_replace (scanner->directives_map,
+ g_strdup (symbol), directives);
+
+ g_strfreev (parts);
+
+}
+
+
+static void
+parse_comment (GISourceScanner *scanner)
+{
+ GString *symbol = NULL;
+ gboolean startofline = FALSE, have_symbol = FALSE, start1 = FALSE, start_symbol = FALSE;
+ int c1, c2;
+
+ c1 = input();
+ c2 = input();
+
+ while (c2 != EOF && !(c1 == '*' && c2 == '/'))
+ {
+ if (c1 == ':')
+ have_symbol = TRUE;
+ else if (c1 == '\n')
+ start1 = TRUE;
+ else if (c1 == '*' && start1)
+ start_symbol = TRUE;
+ else if (!have_symbol && start_symbol)
+ {
+ if (!symbol)
+ symbol = g_string_new ("");
+ if (c1 != ' ')
+ g_string_append_c (symbol, c1);
+ }
+
+ if (c1 == '\n')
+ {
+ ++lineno;
+ startofline = TRUE;
+ }
+
+ c1 = c2;
+ c2 = input();
+
+ if ((c1 != '*' && c1 != ' '))
+ startofline = FALSE;
+
+ if (startofline && (c1 == ' ') && (c2 == '@' || (c2 == 'r') || (c2 == 'R')))
+ {
+ c1 = c2;
+ c2 = input();
+ if (symbol)
+ parse_gtkdoc (scanner, symbol->str, &c1, &c2);
+ }
+ }
+
+ if (symbol)
+ g_string_free (symbol, TRUE);
+
+}
+
+static int
+check_identifier (GISourceScanner *scanner,
+ const char *s)
+{
+ /*
+ * This function checks if `s' is a type name or an
+ * identifier.
+ */
+
+ if (gi_source_scanner_is_typedef (scanner, s)) {
+ return TYPEDEF_NAME;
+ } else if (strcmp (s, "__builtin_va_list") == 0) {
+ return TYPEDEF_NAME;
+ }
+
+ return IDENTIFIER;
+}
+
+static void
+process_directive (GISourceScanner *scanner)
+{
+ /* extract current filename from #line directives */
+ GString *filename_builder;
+ gboolean in_string, found_filename;
+
+ lineno = 0;
+ found_filename = FALSE;
+ in_string = FALSE;
+ filename_builder = g_string_new ("");
+
+ int c = input ();
+ while (c != EOF && c != '\n') {
+ if (!in_string) {
+ if (c == '\"') {
+ in_string = TRUE;
+ found_filename = TRUE;
+ } else if (c >= '0' && c <= '9') {
+ if (!found_filename) {
+ lineno = lineno * 10 + (c - '0');
+ }
+ }
+ } else {
+ if (c == '\"') {
+ in_string = FALSE;
+ } else if (c == '\\') {
+ g_string_append_c (filename_builder, c);
+ c = input ();
+ g_string_append_c (filename_builder, c);
+ } else {
+ g_string_append_c (filename_builder, c);
+ }
+ }
+ c = input ();
+ }
+
+ if (filename_builder->len > 0) {
+ char *filename = g_strcompress (filename_builder->str);
+ g_free (scanner->current_filename);
+ scanner->current_filename = g_realpath(filename);
+ g_free(filename);
+ }
+
+ g_string_free (filename_builder, TRUE);
+}
+
diff --git a/giscanner/scannerparser.y b/giscanner/scannerparser.y
new file mode 100644
index 00000000..45d67891
--- /dev/null
+++ b/giscanner/scannerparser.y
@@ -0,0 +1,1268 @@
+/* GObject introspection: C parser
+ *
+ * Copyright (c) 1997 Sandro Sigala <ssigala@globalnet.it>
+ * Copyright (c) 2007-2008 Jürg Billeter <j@bitron.ch>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include "sourcescanner.h"
+#include "scannerparser.h"
+
+extern FILE *yyin;
+extern int lineno;
+extern char *yytext;
+
+extern int yylex (GISourceScanner *scanner);
+static void yyerror (GISourceScanner *scanner, const char *str);
+
+static int last_enum_value = -1;
+static GHashTable *const_table = NULL;
+%}
+
+%error-verbose
+%union {
+ char *str;
+ GList *list;
+ GISourceSymbol *symbol;
+ GISourceType *ctype;
+ StorageClassSpecifier storage_class_specifier;
+ TypeQualifier type_qualifier;
+ FunctionSpecifier function_specifier;
+ UnaryOperator unary_operator;
+}
+
+%parse-param { GISourceScanner* scanner }
+%lex-param { GISourceScanner* scanner }
+
+%token <str> IDENTIFIER "identifier"
+%token <str> TYPEDEF_NAME "typedef-name"
+
+%token INTEGER FLOATING CHARACTER STRING
+
+%token ELLIPSIS ADDEQ SUBEQ MULEQ DIVEQ MODEQ XOREQ ANDEQ OREQ SL SR
+%token SLEQ SREQ EQ NOTEQ LTEQ GTEQ ANDAND OROR PLUSPLUS MINUSMINUS ARROW
+
+%token AUTO BOOL BREAK CASE CHAR CONST CONTINUE DEFAULT DO DOUBLE ELSE ENUM
+%token EXTERN FLOAT FOR GOTO IF INLINE INT LONG REGISTER RESTRICT RETURN SHORT
+%token SIGNED SIZEOF STATIC STRUCT SWITCH TYPEDEF UNION UNSIGNED VOID VOLATILE
+%token WHILE
+
+%token FUNCTION_MACRO OBJECT_MACRO
+
+%start translation_unit
+
+%type <ctype> declaration_specifiers
+%type <ctype> enum_specifier
+%type <ctype> pointer
+%type <ctype> specifier_qualifier_list
+%type <ctype> type_name
+%type <ctype> struct_or_union
+%type <ctype> struct_or_union_specifier
+%type <ctype> type_specifier
+%type <str> identifier
+%type <str> typedef_name
+%type <str> identifier_or_typedef_name
+%type <symbol> abstract_declarator
+%type <symbol> init_declarator
+%type <symbol> declarator
+%type <symbol> enumerator
+%type <symbol> direct_abstract_declarator
+%type <symbol> direct_declarator
+%type <symbol> parameter_declaration
+%type <symbol> struct_declarator
+%type <list> enumerator_list
+%type <list> identifier_list
+%type <list> init_declarator_list
+%type <list> parameter_type_list
+%type <list> parameter_list
+%type <list> struct_declaration
+%type <list> struct_declaration_list
+%type <list> struct_declarator_list
+%type <storage_class_specifier> storage_class_specifier
+%type <type_qualifier> type_qualifier
+%type <type_qualifier> type_qualifier_list
+%type <function_specifier> function_specifier
+%type <symbol> expression
+%type <symbol> constant_expression
+%type <symbol> conditional_expression
+%type <symbol> logical_and_expression
+%type <symbol> logical_or_expression
+%type <symbol> inclusive_or_expression
+%type <symbol> exclusive_or_expression
+%type <symbol> multiplicative_expression
+%type <symbol> additive_expression
+%type <symbol> shift_expression
+%type <symbol> relational_expression
+%type <symbol> equality_expression
+%type <symbol> and_expression
+%type <symbol> cast_expression
+%type <symbol> assignment_expression
+%type <symbol> unary_expression
+%type <symbol> postfix_expression
+%type <symbol> primary_expression
+%type <unary_operator> unary_operator
+%type <str> function_macro
+%type <str> object_macro
+%type <symbol> strings
+
+%%
+
+/* A.2.1 Expressions. */
+
+primary_expression
+ : identifier
+ {
+ $$ = g_hash_table_lookup (const_table, $1);
+ if ($$ == NULL) {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ } else {
+ $$ = gi_source_symbol_ref ($$);
+ }
+ }
+ | INTEGER
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ if (g_str_has_prefix (yytext, "0x") && strlen (yytext) > 2) {
+ $$->const_int = strtol (yytext + 2, NULL, 16);
+ } else if (g_str_has_prefix (yytext, "0") && strlen (yytext) > 1) {
+ $$->const_int = strtol (yytext + 1, NULL, 8);
+ } else {
+ $$->const_int = atoi (yytext);
+ }
+ }
+ | CHARACTER
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | FLOATING
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | strings
+ | '(' expression ')'
+ {
+ $$ = $2;
+ }
+ ;
+
+/* concatenate adjacent string literal tokens */
+strings
+ : STRING
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ yytext[strlen (yytext) - 1] = '\0';
+ $$->const_string = g_strcompress (yytext + 1);
+ }
+ | strings STRING
+ {
+ char *strings, *string2;
+ $$ = $1;
+ yytext[strlen (yytext) - 1] = '\0';
+ string2 = g_strcompress (yytext + 1);
+ strings = g_strconcat ($$->const_string, string2, NULL);
+ g_free ($$->const_string);
+ g_free (string2);
+ $$->const_string = strings;
+ }
+ ;
+
+identifier
+ : IDENTIFIER
+ {
+ $$ = g_strdup (yytext);
+ }
+ ;
+
+identifier_or_typedef_name
+ : identifier
+ | typedef_name
+ ;
+
+postfix_expression
+ : primary_expression
+ | postfix_expression '[' expression ']'
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression '(' argument_expression_list ')'
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression '(' ')'
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression '.' identifier_or_typedef_name
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression ARROW identifier_or_typedef_name
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression PLUSPLUS
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | postfix_expression MINUSMINUS
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ ;
+
+argument_expression_list
+ : assignment_expression
+ | argument_expression_list ',' assignment_expression
+ ;
+
+unary_expression
+ : postfix_expression
+ | PLUSPLUS unary_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | MINUSMINUS unary_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | unary_operator cast_expression
+ {
+ switch ($1) {
+ case UNARY_PLUS:
+ $$ = $2;
+ break;
+ case UNARY_MINUS:
+ $$ = $2;
+ $$->const_int = -$2->const_int;
+ break;
+ case UNARY_BITWISE_COMPLEMENT:
+ $$ = $2;
+ $$->const_int = ~$2->const_int;
+ break;
+ case UNARY_LOGICAL_NEGATION:
+ $$ = $2;
+ $$->const_int = !gi_source_symbol_get_const_boolean ($2);
+ break;
+ default:
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ break;
+ }
+ }
+ | SIZEOF unary_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | SIZEOF '(' type_name ')'
+ {
+ ctype_free ($3);
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ ;
+
+unary_operator
+ : '&'
+ {
+ $$ = UNARY_ADDRESS_OF;
+ }
+ | '*'
+ {
+ $$ = UNARY_POINTER_INDIRECTION;
+ }
+ | '+'
+ {
+ $$ = UNARY_PLUS;
+ }
+ | '-'
+ {
+ $$ = UNARY_MINUS;
+ }
+ | '~'
+ {
+ $$ = UNARY_BITWISE_COMPLEMENT;
+ }
+ | '!'
+ {
+ $$ = UNARY_LOGICAL_NEGATION;
+ }
+ ;
+
+cast_expression
+ : unary_expression
+ | '(' type_name ')' cast_expression
+ {
+ ctype_free ($2);
+ $$ = $4;
+ }
+ ;
+
+multiplicative_expression
+ : cast_expression
+ | multiplicative_expression '*' cast_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int * $3->const_int;
+ }
+ | multiplicative_expression '/' cast_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ if ($3->const_int != 0) {
+ $$->const_int = $1->const_int / $3->const_int;
+ }
+ }
+ | multiplicative_expression '%' cast_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int % $3->const_int;
+ }
+ ;
+
+additive_expression
+ : multiplicative_expression
+ | additive_expression '+' multiplicative_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int + $3->const_int;
+ }
+ | additive_expression '-' multiplicative_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int - $3->const_int;
+ }
+ ;
+
+shift_expression
+ : additive_expression
+ | shift_expression SL additive_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int << $3->const_int;
+ }
+ | shift_expression SR additive_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int >> $3->const_int;
+ }
+ ;
+
+relational_expression
+ : shift_expression
+ | relational_expression '<' shift_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int < $3->const_int;
+ }
+ | relational_expression '>' shift_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int > $3->const_int;
+ }
+ | relational_expression LTEQ shift_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int <= $3->const_int;
+ }
+ | relational_expression GTEQ shift_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int >= $3->const_int;
+ }
+ ;
+
+equality_expression
+ : relational_expression
+ | equality_expression EQ relational_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int == $3->const_int;
+ }
+ | equality_expression NOTEQ relational_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int != $3->const_int;
+ }
+ ;
+
+and_expression
+ : equality_expression
+ | and_expression '&' equality_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int & $3->const_int;
+ }
+ ;
+
+exclusive_or_expression
+ : and_expression
+ | exclusive_or_expression '^' and_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int ^ $3->const_int;
+ }
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression
+ | inclusive_or_expression '|' exclusive_or_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int = $1->const_int | $3->const_int;
+ }
+ ;
+
+logical_and_expression
+ : inclusive_or_expression
+ | logical_and_expression ANDAND inclusive_or_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int =
+ gi_source_symbol_get_const_boolean ($1) &&
+ gi_source_symbol_get_const_boolean ($3);
+ }
+ ;
+
+logical_or_expression
+ : logical_and_expression
+ | logical_or_expression OROR logical_and_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_CONST);
+ $$->const_int_set = TRUE;
+ $$->const_int =
+ gi_source_symbol_get_const_boolean ($1) ||
+ gi_source_symbol_get_const_boolean ($3);
+ }
+ ;
+
+conditional_expression
+ : logical_or_expression
+ | logical_or_expression '?' expression ':' conditional_expression
+ {
+ $$ = gi_source_symbol_get_const_boolean ($1) ? $3 : $5;
+ }
+ ;
+
+assignment_expression
+ : conditional_expression
+ | unary_expression assignment_operator assignment_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ ;
+
+assignment_operator
+ : '='
+ | MULEQ
+ | DIVEQ
+ | MODEQ
+ | ADDEQ
+ | SUBEQ
+ | SLEQ
+ | SREQ
+ | ANDEQ
+ | XOREQ
+ | OREQ
+ ;
+
+expression
+ : assignment_expression
+ | expression ',' assignment_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ ;
+
+constant_expression
+ : conditional_expression
+ ;
+
+/* A.2.2 Declarations. */
+
+declaration
+ : declaration_specifiers init_declarator_list ';'
+ {
+ GList *l;
+ for (l = $2; l != NULL; l = l->next) {
+ GISourceSymbol *sym = l->data;
+ gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
+ if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
+ sym->type = CSYMBOL_TYPE_TYPEDEF;
+ } else if (sym->base_type->type == CTYPE_FUNCTION) {
+ sym->type = CSYMBOL_TYPE_FUNCTION;
+ } else {
+ sym->type = CSYMBOL_TYPE_OBJECT;
+ }
+ gi_source_scanner_add_symbol (scanner, sym);
+ gi_source_symbol_unref (sym);
+ }
+ ctype_free ($1);
+ }
+ | declaration_specifiers ';'
+ {
+ ctype_free ($1);
+ }
+ ;
+
+declaration_specifiers
+ : storage_class_specifier declaration_specifiers
+ {
+ $$ = $2;
+ $$->storage_class_specifier |= $1;
+ }
+ | storage_class_specifier
+ {
+ $$ = gi_source_type_new (CTYPE_INVALID);
+ $$->storage_class_specifier |= $1;
+ }
+ | type_specifier declaration_specifiers
+ {
+ $$ = $1;
+ $$->base_type = $2;
+ }
+ | type_specifier
+ | type_qualifier declaration_specifiers
+ {
+ $$ = $2;
+ $$->type_qualifier |= $1;
+ }
+ | type_qualifier
+ {
+ $$ = gi_source_type_new (CTYPE_INVALID);
+ $$->type_qualifier |= $1;
+ }
+ | function_specifier declaration_specifiers
+ {
+ $$ = $2;
+ $$->function_specifier |= $1;
+ }
+ | function_specifier
+ {
+ $$ = gi_source_type_new (CTYPE_INVALID);
+ $$->function_specifier |= $1;
+ }
+ ;
+
+init_declarator_list
+ : init_declarator
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | init_declarator_list ',' init_declarator
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+init_declarator
+ : declarator
+ | declarator '=' initializer
+ ;
+
+storage_class_specifier
+ : TYPEDEF
+ {
+ $$ = STORAGE_CLASS_TYPEDEF;
+ }
+ | EXTERN
+ {
+ $$ = STORAGE_CLASS_EXTERN;
+ }
+ | STATIC
+ {
+ $$ = STORAGE_CLASS_STATIC;
+ }
+ | AUTO
+ {
+ $$ = STORAGE_CLASS_AUTO;
+ }
+ | REGISTER
+ {
+ $$ = STORAGE_CLASS_REGISTER;
+ }
+ ;
+
+type_specifier
+ : VOID
+ {
+ $$ = gi_source_type_new (CTYPE_VOID);
+ }
+ | CHAR
+ {
+ $$ = gi_source_basic_type_new ("char");
+ }
+ | SHORT
+ {
+ $$ = gi_source_basic_type_new ("short");
+ }
+ | INT
+ {
+ $$ = gi_source_basic_type_new ("int");
+ }
+ | LONG
+ {
+ $$ = gi_source_basic_type_new ("long");
+ }
+ | FLOAT
+ {
+ $$ = gi_source_basic_type_new ("float");
+ }
+ | DOUBLE
+ {
+ $$ = gi_source_basic_type_new ("double");
+ }
+ | SIGNED
+ {
+ $$ = gi_source_basic_type_new ("signed");
+ }
+ | UNSIGNED
+ {
+ $$ = gi_source_basic_type_new ("unsigned");
+ }
+ | BOOL
+ {
+ $$ = gi_source_basic_type_new ("bool");
+ }
+ | struct_or_union_specifier
+ | enum_specifier
+ | typedef_name
+ {
+ $$ = gi_source_typedef_new ($1);
+ g_free ($1);
+ }
+ ;
+
+struct_or_union_specifier
+ : struct_or_union identifier_or_typedef_name '{' struct_declaration_list '}'
+ {
+ $$ = $1;
+ $$->name = $2;
+ $$->child_list = $4;
+
+ GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ if ($$->type == CTYPE_STRUCT) {
+ sym->type = CSYMBOL_TYPE_STRUCT;
+ } else if ($$->type == CTYPE_UNION) {
+ sym->type = CSYMBOL_TYPE_UNION;
+ } else {
+ g_assert_not_reached ();
+ }
+ sym->ident = g_strdup ($$->name);
+ sym->base_type = gi_source_type_copy ($$);
+ gi_source_scanner_add_symbol (scanner, sym);
+ gi_source_symbol_unref (sym);
+ }
+ | struct_or_union '{' struct_declaration_list '}'
+ {
+ $$ = $1;
+ $$->child_list = $3;
+ }
+ | struct_or_union identifier_or_typedef_name
+ {
+ $$ = $1;
+ $$->name = $2;
+ }
+ ;
+
+struct_or_union
+ : STRUCT
+ {
+ $$ = gi_source_struct_new (NULL);
+ }
+ | UNION
+ {
+ $$ = gi_source_union_new (NULL);
+ }
+ ;
+
+struct_declaration_list
+ : struct_declaration
+ | struct_declaration_list struct_declaration
+ {
+ $$ = g_list_concat ($1, $2);
+ }
+ ;
+
+struct_declaration
+ : specifier_qualifier_list struct_declarator_list ';'
+ {
+ GList *l;
+ $$ = NULL;
+ for (l = $2; l != NULL; l = l->next) {
+ GISourceSymbol *sym = l->data;
+ if ($1->storage_class_specifier & STORAGE_CLASS_TYPEDEF) {
+ sym->type = CSYMBOL_TYPE_TYPEDEF;
+ }
+ gi_source_symbol_merge_type (sym, gi_source_type_copy ($1));
+ $$ = g_list_append ($$, sym);
+ }
+ ctype_free ($1);
+ }
+ ;
+
+specifier_qualifier_list
+ : type_specifier specifier_qualifier_list
+ {
+ $$ = $1;
+ $$->base_type = $2;
+ }
+ | type_specifier
+ | type_qualifier specifier_qualifier_list
+ {
+ $$ = $2;
+ $$->type_qualifier |= $1;
+ }
+ | type_qualifier
+ {
+ $$ = gi_source_type_new (CTYPE_INVALID);
+ $$->type_qualifier |= $1;
+ }
+ ;
+
+struct_declarator_list
+ : struct_declarator
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | struct_declarator_list ',' struct_declarator
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+struct_declarator
+ : /* empty, support for anonymous structs and unions */
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | declarator
+ | ':' constant_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ }
+ | declarator ':' constant_expression
+ ;
+
+enum_specifier
+ : ENUM identifier_or_typedef_name '{' enumerator_list '}'
+ {
+ $$ = gi_source_enum_new ($2);
+ $$->child_list = $4;
+ last_enum_value = -1;
+ }
+ | ENUM '{' enumerator_list '}'
+ {
+ $$ = gi_source_enum_new (NULL);
+ $$->child_list = $3;
+ last_enum_value = -1;
+ }
+ | ENUM identifier_or_typedef_name '{' enumerator_list ',' '}'
+ {
+ $$ = gi_source_enum_new ($2);
+ $$->child_list = $4;
+ last_enum_value = -1;
+ }
+ | ENUM '{' enumerator_list ',' '}'
+ {
+ $$ = gi_source_enum_new (NULL);
+ $$->child_list = $3;
+ last_enum_value = -1;
+ }
+ | ENUM identifier_or_typedef_name
+ {
+ $$ = gi_source_enum_new ($2);
+ }
+ ;
+
+enumerator_list
+ : enumerator
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | enumerator_list ',' enumerator
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+enumerator
+ : identifier
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT);
+ $$->ident = $1;
+ $$->const_int_set = TRUE;
+ $$->const_int = ++last_enum_value;
+ g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
+ }
+ | identifier '=' constant_expression
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_OBJECT);
+ $$->ident = $1;
+ $$->const_int_set = TRUE;
+ $$->const_int = $3->const_int;
+ last_enum_value = $$->const_int;
+ g_hash_table_insert (const_table, g_strdup ($$->ident), gi_source_symbol_ref ($$));
+ }
+ ;
+
+type_qualifier
+ : CONST
+ {
+ $$ = TYPE_QUALIFIER_CONST;
+ }
+ | RESTRICT
+ {
+ $$ = TYPE_QUALIFIER_RESTRICT;
+ }
+ | VOLATILE
+ {
+ $$ = TYPE_QUALIFIER_VOLATILE;
+ }
+ ;
+
+function_specifier
+ : INLINE
+ {
+ $$ = FUNCTION_INLINE;
+ }
+ ;
+
+declarator
+ : pointer direct_declarator
+ {
+ $$ = $2;
+ gi_source_symbol_merge_type ($$, $1);
+ }
+ | direct_declarator
+ ;
+
+direct_declarator
+ : identifier
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ $$->ident = $1;
+ }
+ | '(' declarator ')'
+ {
+ $$ = $2;
+ }
+ | direct_declarator '[' assignment_expression ']'
+ {
+ $$ = $1;
+ gi_source_symbol_merge_type ($$, gi_source_array_new ());
+ }
+ | direct_declarator '[' ']'
+ {
+ $$ = $1;
+ gi_source_symbol_merge_type ($$, gi_source_array_new ());
+ }
+ | direct_declarator '(' parameter_type_list ')'
+ {
+ GISourceType *func = gi_source_function_new ();
+ // ignore (void) parameter list
+ if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
+ func->child_list = $3;
+ }
+ $$ = $1;
+ gi_source_symbol_merge_type ($$, func);
+ }
+ | direct_declarator '(' identifier_list ')'
+ {
+ GISourceType *func = gi_source_function_new ();
+ func->child_list = $3;
+ $$ = $1;
+ gi_source_symbol_merge_type ($$, func);
+ }
+ | direct_declarator '(' ')'
+ {
+ GISourceType *func = gi_source_function_new ();
+ $$ = $1;
+ gi_source_symbol_merge_type ($$, func);
+ }
+ ;
+
+pointer
+ : '*' type_qualifier_list
+ {
+ $$ = gi_source_pointer_new (NULL);
+ $$->type_qualifier = $2;
+ }
+ | '*'
+ {
+ $$ = gi_source_pointer_new (NULL);
+ }
+ | '*' type_qualifier_list pointer
+ {
+ $$ = gi_source_pointer_new ($3);
+ $$->type_qualifier = $2;
+ }
+ | '*' pointer
+ {
+ $$ = gi_source_pointer_new ($2);
+ }
+ ;
+
+type_qualifier_list
+ : type_qualifier
+ | type_qualifier_list type_qualifier
+ {
+ $$ = $1 | $2;
+ }
+ ;
+
+parameter_type_list
+ : parameter_list
+ | parameter_list ',' ELLIPSIS
+ ;
+
+parameter_list
+ : parameter_declaration
+ {
+ $$ = g_list_append (NULL, $1);
+ }
+ | parameter_list ',' parameter_declaration
+ {
+ $$ = g_list_append ($1, $3);
+ }
+ ;
+
+parameter_declaration
+ : declaration_specifiers declarator
+ {
+ $$ = $2;
+ gi_source_symbol_merge_type ($$, $1);
+ }
+ | declaration_specifiers abstract_declarator
+ {
+ $$ = $2;
+ gi_source_symbol_merge_type ($$, $1);
+ }
+ | declaration_specifiers
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ $$->base_type = $1;
+ }
+ ;
+
+identifier_list
+ : identifier
+ {
+ GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ sym->ident = $1;
+ $$ = g_list_append (NULL, sym);
+ }
+ | identifier_list ',' identifier
+ {
+ GISourceSymbol *sym = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ sym->ident = $3;
+ $$ = g_list_append ($1, sym);
+ }
+ ;
+
+type_name
+ : specifier_qualifier_list
+ | specifier_qualifier_list abstract_declarator
+ ;
+
+abstract_declarator
+ : pointer
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ gi_source_symbol_merge_type ($$, $1);
+ }
+ | direct_abstract_declarator
+ | pointer direct_abstract_declarator
+ {
+ $$ = $2;
+ gi_source_symbol_merge_type ($$, $1);
+ }
+ ;
+
+direct_abstract_declarator
+ : '(' abstract_declarator ')'
+ {
+ $$ = $2;
+ }
+ | '[' ']'
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ gi_source_symbol_merge_type ($$, gi_source_array_new ());
+ }
+ | '[' assignment_expression ']'
+ {
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ gi_source_symbol_merge_type ($$, gi_source_array_new ());
+ }
+ | direct_abstract_declarator '[' ']'
+ {
+ $$ = $1;
+ gi_source_symbol_merge_type ($$, gi_source_array_new ());
+ }
+ | direct_abstract_declarator '[' assignment_expression ']'
+ {
+ $$ = $1;
+ gi_source_symbol_merge_type ($$, gi_source_array_new ());
+ }
+ | '(' ')'
+ {
+ GISourceType *func = gi_source_function_new ();
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ gi_source_symbol_merge_type ($$, func);
+ }
+ | '(' parameter_type_list ')'
+ {
+ GISourceType *func = gi_source_function_new ();
+ // ignore (void) parameter list
+ if ($2 != NULL && ($2->next != NULL || ((GISourceSymbol *) $2->data)->base_type->type != CTYPE_VOID)) {
+ func->child_list = $2;
+ }
+ $$ = gi_source_symbol_new (CSYMBOL_TYPE_INVALID);
+ gi_source_symbol_merge_type ($$, func);
+ }
+ | direct_abstract_declarator '(' ')'
+ {
+ GISourceType *func = gi_source_function_new ();
+ $$ = $1;
+ gi_source_symbol_merge_type ($$, func);
+ }
+ | direct_abstract_declarator '(' parameter_type_list ')'
+ {
+ GISourceType *func = gi_source_function_new ();
+ // ignore (void) parameter list
+ if ($3 != NULL && ($3->next != NULL || ((GISourceSymbol *) $3->data)->base_type->type != CTYPE_VOID)) {
+ func->child_list = $3;
+ }
+ $$ = $1;
+ gi_source_symbol_merge_type ($$, func);
+ }
+ ;
+
+typedef_name
+ : TYPEDEF_NAME
+ {
+ $$ = g_strdup (yytext);
+ }
+ ;
+
+initializer
+ : assignment_expression
+ | '{' initializer_list '}'
+ | '{' initializer_list ',' '}'
+ ;
+
+initializer_list
+ : initializer
+ | initializer_list ',' initializer
+ ;
+
+/* A.2.3 Statements. */
+
+statement
+ : labeled_statement
+ | compound_statement
+ | expression_statement
+ | selection_statement
+ | iteration_statement
+ | jump_statement
+ ;
+
+labeled_statement
+ : identifier_or_typedef_name ':' statement
+ | CASE constant_expression ':' statement
+ | DEFAULT ':' statement
+ ;
+
+compound_statement
+ : '{' '}'
+ | '{' block_item_list '}'
+ ;
+
+block_item_list
+ : block_item
+ | block_item_list block_item
+ ;
+
+block_item
+ : declaration
+ | statement
+ ;
+
+expression_statement
+ : ';'
+ | expression ';'
+ ;
+
+selection_statement
+ : IF '(' expression ')' statement
+ | IF '(' expression ')' statement ELSE statement
+ | SWITCH '(' expression ')' statement
+ ;
+
+iteration_statement
+ : WHILE '(' expression ')' statement
+ | DO statement WHILE '(' expression ')' ';'
+ | FOR '(' ';' ';' ')' statement
+ | FOR '(' expression ';' ';' ')' statement
+ | FOR '(' ';' expression ';' ')' statement
+ | FOR '(' expression ';' expression ';' ')' statement
+ | FOR '(' ';' ';' expression ')' statement
+ | FOR '(' expression ';' ';' expression ')' statement
+ | FOR '(' ';' expression ';' expression ')' statement
+ | FOR '(' expression ';' expression ';' expression ')' statement
+ ;
+
+jump_statement
+ : GOTO identifier_or_typedef_name ';'
+ | CONTINUE ';'
+ | BREAK ';'
+ | RETURN ';'
+ | RETURN expression ';'
+ ;
+
+/* A.2.4 External definitions. */
+
+translation_unit
+ : external_declaration
+ | translation_unit external_declaration
+ ;
+
+external_declaration
+ : function_definition
+ | declaration
+ | macro
+ ;
+
+function_definition
+ : declaration_specifiers declarator declaration_list compound_statement
+ | declaration_specifiers declarator compound_statement
+ ;
+
+declaration_list
+ : declaration
+ | declaration_list declaration
+ ;
+
+/* Macros */
+
+function_macro
+ : FUNCTION_MACRO
+ {
+ $$ = g_strdup (yytext + strlen ("#define "));
+ }
+ ;
+
+object_macro
+ : OBJECT_MACRO
+ {
+ $$ = g_strdup (yytext + strlen ("#define "));
+ }
+ ;
+
+function_macro_define
+ : function_macro '(' identifier_list ')'
+ ;
+
+object_macro_define
+ : object_macro constant_expression
+ {
+ if ($2->const_int_set || $2->const_string != NULL) {
+ $2->ident = $1;
+ gi_source_scanner_add_symbol (scanner, $2);
+ gi_source_symbol_unref ($2);
+ }
+ }
+ ;
+
+macro
+ : function_macro_define
+ | object_macro_define
+ | error
+ ;
+
+%%
+static void
+yyerror (GISourceScanner *scanner, const char *s)
+{
+ /* ignore errors while doing a macro scan as not all object macros
+ * have valid expressions */
+ if (!scanner->macro_scan)
+ {
+ fprintf(stderr, "%s:%d: %s\n",
+ scanner->current_filename, lineno, s);
+ }
+}
+
+gboolean
+gi_source_scanner_parse_file (GISourceScanner *scanner, FILE *file)
+{
+ g_return_val_if_fail (file != NULL, FALSE);
+
+ const_table = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, (GDestroyNotify)gi_source_symbol_unref);
+
+ lineno = 1;
+ yyin = file;
+ yyparse (scanner);
+
+ g_hash_table_destroy (const_table);
+ const_table = NULL;
+
+ yyin = NULL;
+
+ return TRUE;
+}
+
+gboolean
+gi_source_scanner_lex_filename (GISourceScanner *scanner, const gchar *filename)
+{
+ yyin = fopen (filename, "r");
+
+ while (yylex (scanner) != YYEOF)
+ ;
+
+ fclose (yyin);
+
+ return TRUE;
+}
diff --git a/tools/sourcescanner.c b/giscanner/sourcescanner.c
index 8354b1b5..bb916e88 100644
--- a/tools/sourcescanner.c
+++ b/giscanner/sourcescanner.c
@@ -236,6 +236,13 @@ gi_source_scanner_is_typedef (GISourceScanner *scanner,
}
void
+gi_source_scanner_set_macro_scan (GISourceScanner *scanner,
+ gboolean macro_scan)
+{
+ scanner->macro_scan = macro_scan;
+}
+
+void
gi_source_scanner_add_symbol (GISourceScanner *scanner,
GISourceSymbol *symbol)
{
diff --git a/tools/sourcescanner.h b/giscanner/sourcescanner.h
index 71236ce9..c1365e02 100644
--- a/tools/sourcescanner.h
+++ b/giscanner/sourcescanner.h
@@ -125,14 +125,14 @@ struct _GISourceType
FunctionSpecifier function_specifier;
char *name;
GISourceType *base_type;
- GList *child_list;
+ GList *child_list; /* list of GISourceSymbol */
};
struct _GISourceDirective
{
char *name;
char *value;
- GSList *options;
+ GSList *options; /* list of options (key=value) */
};
GISourceScanner * gi_source_scanner_new (void);
@@ -140,6 +140,8 @@ gboolean gi_source_scanner_lex_filename (GISourceScanner *igener
const gchar *filename);
gboolean gi_source_scanner_parse_file (GISourceScanner *igenerator,
FILE *file);
+void gi_source_scanner_set_macro_scan (GISourceScanner *scanner,
+ gboolean macro_scan);
GSList * gi_source_scanner_get_symbols (GISourceScanner *scanner);
void gi_source_scanner_free (GISourceScanner *scanner);
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 46fff6bf..545050a9 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,16 +1,14 @@
## Process this file with automake to produce Makefile.in
-INCLUDES = -DGIREPO_DEFAULT_SEARCH_PATH="\"$(libdir)\""
-BUILT_SOURCES = scannerparser.c scannerparser.h scannerlexer.c scannerlexer.h \
- gmetadata-header.c
+INCLUDES = \
+ -DGIREPO_DEFAULT_SEARCH_PATH="\"$(libdir)\"" \
+ -I$(top_srcdir)/girepository \
+ -I$(top_srcdir)/giscanner
+BUILT_SOURCES = gmetadata-header.c
-CLEANFILES = scannerparser.c scannerparser.h scannerlexer.c scannerlexer.h gmetadata-header.c
-AM_YFLAGS = -d -t
+CLEANFILES = gmetadata-header.c
EXTRA_DIST = quote-file.sh
-# Why do I have to do this automake?
-scannerlexer.h: scannerlexer.c
-
noinst_LTLIBRARIES = libgirepository-parser.la
bin_PROGRAMS = g-idl-compiler g-idl-generate g-idl-scanner
@@ -32,28 +30,28 @@ libgirepository_parser_la_SOURCES = \
gidlcompilertypenode.h \
gmetadata-header.c
-libgirepository_parser_la_CFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
+libgirepository_parser_la_CFLAGS = $(GIREPO_CFLAGS)
g_idl_compiler_SOURCES = compiler.c
-g_idl_compiler_CFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
+g_idl_compiler_CFLAGS = $(GIREPO_CFLAGS)
g_idl_compiler_LDADD = $(GIREPO_LIBS) $(top_builddir)/girepository/libgirepository.la libgirepository-parser.la
g_idl_generate_SOURCES = generate.c
-g_idl_generate_CFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
+g_idl_generate_CFLAGS = $(GIREPO_CFLAGS)
g_idl_generate_LDADD = $(GIREPO_LIBS) $(top_builddir)/girepository/libgirepository.la
g_idl_scanner_SOURCES = \
- sourcescanner.c \
- sourcescanner.h \
scanner.c \
scanner.h \
- scannerlexer.l \
- scannerparser.y \
gidlwriter.c \
- gidlwriter.h \
- grealpath.h
-g_idl_scanner_CFLAGS = $(GIREPO_CFLAGS) $(SCANNER_CFLAGS) -I$(top_srcdir)/girepository
-g_idl_scanner_LDADD = $(GIREPO_LIBS) $(SCANNER_LIBS) $(top_builddir)/girepository/libgirepository.la libgirepository-parser.la
+ gidlwriter.h
+g_idl_scanner_CFLAGS = $(GIREPO_CFLAGS) $(SCANNER_CFLAGS)
+g_idl_scanner_LDADD = \
+ $(GIREPO_LIBS) \
+ $(SCANNER_LIBS) \
+ $(top_builddir)/girepository/libgirepository.la \
+ $(top_builddir)/giscanner/libgiscanner.la \
+ libgirepository-parser.la
GCOVSOURCES = \
$(libgirepository_la_SOURCES) \