summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Graunke <kenneth@whitecape.org>2010-06-21 11:22:11 -0700
committerKenneth Graunke <kenneth@whitecape.org>2010-06-21 11:22:11 -0700
commit6f510a49d2f3271432844d6b7e2bfe459b2126d4 (patch)
tree7ad316228b4353bbdf0070d61a754b84b29c1a30
parentf3eb42d200bb78afae64af6862e2b12396226707 (diff)
parent2fb30a2e492e466a7b383e8ca430ba7371b443ee (diff)
Merge Carl's preprocessor into the glcpp subdirectory.
-rw-r--r--glcpp/.gitignore7
-rw-r--r--glcpp/Makefile25
-rw-r--r--glcpp/README30
-rw-r--r--glcpp/glcpp-lex.l202
-rw-r--r--glcpp/glcpp-parse.y1602
-rw-r--r--glcpp/glcpp.c41
-rw-r--r--glcpp/glcpp.h195
-rw-r--r--glcpp/hash_table.c159
-rw-r--r--glcpp/hash_table.h125
-rw-r--r--glcpp/main/imports.h6
-rw-r--r--glcpp/main/simple_list.h235
-rw-r--r--glcpp/tests/000-content-with-spaces.c1
-rw-r--r--glcpp/tests/000-content-with-spaces.c.expected1
-rw-r--r--glcpp/tests/001-define.c2
-rw-r--r--glcpp/tests/001-define.c.expected2
-rw-r--r--glcpp/tests/002-define-chain.c3
-rw-r--r--glcpp/tests/002-define-chain.c.expected3
-rw-r--r--glcpp/tests/003-define-chain-reverse.c3
-rw-r--r--glcpp/tests/003-define-chain-reverse.c.expected3
-rw-r--r--glcpp/tests/004-define-recursive.c6
-rw-r--r--glcpp/tests/004-define-recursive.c.expected6
-rw-r--r--glcpp/tests/005-define-composite-chain.c3
-rw-r--r--glcpp/tests/005-define-composite-chain.c.expected3
-rw-r--r--glcpp/tests/006-define-composite-chain-reverse.c3
-rw-r--r--glcpp/tests/006-define-composite-chain-reverse.c.expected3
-rw-r--r--glcpp/tests/007-define-composite-recursive.c6
-rw-r--r--glcpp/tests/007-define-composite-recursive.c.expected6
-rw-r--r--glcpp/tests/008-define-empty.c2
-rw-r--r--glcpp/tests/008-define-empty.c.expected2
-rw-r--r--glcpp/tests/009-undef.c4
-rw-r--r--glcpp/tests/009-undef.c.expected4
-rw-r--r--glcpp/tests/010-undef-re-define.c6
-rw-r--r--glcpp/tests/010-undef-re-define.c.expected6
-rw-r--r--glcpp/tests/011-define-func-empty.c2
-rw-r--r--glcpp/tests/011-define-func-empty.c.expected2
-rw-r--r--glcpp/tests/012-define-func-no-args.c2
-rw-r--r--glcpp/tests/012-define-func-no-args.c.expected2
-rw-r--r--glcpp/tests/013-define-func-1-arg-unused.c2
-rw-r--r--glcpp/tests/013-define-func-1-arg-unused.c.expected2
-rw-r--r--glcpp/tests/014-define-func-2-arg-unused.c2
-rw-r--r--glcpp/tests/014-define-func-2-arg-unused.c.expected2
-rw-r--r--glcpp/tests/015-define-object-with-parens.c4
-rw-r--r--glcpp/tests/015-define-object-with-parens.c.expected4
-rw-r--r--glcpp/tests/016-define-func-1-arg.c2
-rw-r--r--glcpp/tests/016-define-func-1-arg.c.expected2
-rw-r--r--glcpp/tests/017-define-func-2-args.c2
-rw-r--r--glcpp/tests/017-define-func-2-args.c.expected2
-rw-r--r--glcpp/tests/018-define-func-macro-as-parameter.c3
-rw-r--r--glcpp/tests/018-define-func-macro-as-parameter.c.expected3
-rw-r--r--glcpp/tests/019-define-func-1-arg-multi.c2
-rw-r--r--glcpp/tests/019-define-func-1-arg-multi.c.expected2
-rw-r--r--glcpp/tests/020-define-func-2-arg-multi.c2
-rw-r--r--glcpp/tests/020-define-func-2-arg-multi.c.expected2
-rw-r--r--glcpp/tests/021-define-func-compose.c3
-rw-r--r--glcpp/tests/021-define-func-compose.c.expected3
-rw-r--r--glcpp/tests/022-define-func-arg-with-parens.c2
-rw-r--r--glcpp/tests/022-define-func-arg-with-parens.c.expected2
-rw-r--r--glcpp/tests/023-define-extra-whitespace.c8
-rw-r--r--glcpp/tests/023-define-extra-whitespace.c.expected8
-rw-r--r--glcpp/tests/024-define-chain-to-self-recursion.c3
-rw-r--r--glcpp/tests/024-define-chain-to-self-recursion.c.expected3
-rw-r--r--glcpp/tests/025-func-macro-as-non-macro.c2
-rw-r--r--glcpp/tests/025-func-macro-as-non-macro.c.expected2
-rw-r--r--glcpp/tests/026-define-func-extra-newlines.c6
-rw-r--r--glcpp/tests/026-define-func-extra-newlines.c.expected3
-rw-r--r--glcpp/tests/027-define-chain-obj-to-func.c3
-rw-r--r--glcpp/tests/027-define-chain-obj-to-func.c.expected3
-rw-r--r--glcpp/tests/028-define-chain-obj-to-non-func.c3
-rw-r--r--glcpp/tests/028-define-chain-obj-to-non-func.c.expected3
-rw-r--r--glcpp/tests/029-define-chain-obj-to-func-with-args.c3
-rw-r--r--glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected3
-rw-r--r--glcpp/tests/030-define-chain-obj-to-func-compose.c4
-rw-r--r--glcpp/tests/030-define-chain-obj-to-func-compose.c.expected4
-rw-r--r--glcpp/tests/031-define-chain-func-to-func-compose.c4
-rw-r--r--glcpp/tests/031-define-chain-func-to-func-compose.c.expected4
-rw-r--r--glcpp/tests/032-define-func-self-recurse.c2
-rw-r--r--glcpp/tests/032-define-func-self-recurse.c.expected2
-rw-r--r--glcpp/tests/033-define-func-self-compose.c2
-rw-r--r--glcpp/tests/033-define-func-self-compose.c.expected2
-rw-r--r--glcpp/tests/034-define-func-self-compose-non-func.c2
-rw-r--r--glcpp/tests/034-define-func-self-compose-non-func.c.expected2
-rw-r--r--glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c2
-rw-r--r--glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected2
-rw-r--r--glcpp/tests/036-define-func-non-macro-multi-token-argument.c3
-rw-r--r--glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected3
-rw-r--r--glcpp/tests/037-finalize-unexpanded-macro.c3
-rw-r--r--glcpp/tests/037-finalize-unexpanded-macro.c.expected3
-rw-r--r--glcpp/tests/038-func-arg-with-commas.c2
-rw-r--r--glcpp/tests/038-func-arg-with-commas.c.expected2
-rw-r--r--glcpp/tests/039-func-arg-obj-macro-with-comma.c3
-rw-r--r--glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected3
-rw-r--r--glcpp/tests/040-token-pasting.c2
-rw-r--r--glcpp/tests/040-token-pasting.c.expected2
-rw-r--r--glcpp/tests/041-if-0.c5
-rw-r--r--glcpp/tests/041-if-0.c.expected5
-rw-r--r--glcpp/tests/042-if-1.c5
-rw-r--r--glcpp/tests/042-if-1.c.expected5
-rw-r--r--glcpp/tests/043-if-0-else.c7
-rw-r--r--glcpp/tests/043-if-0-else.c.expected7
-rw-r--r--glcpp/tests/044-if-1-else.c7
-rw-r--r--glcpp/tests/044-if-1-else.c.expected7
-rw-r--r--glcpp/tests/045-if-0-elif.c11
-rw-r--r--glcpp/tests/045-if-0-elif.c.expected11
-rw-r--r--glcpp/tests/046-if-1-elsif.c11
-rw-r--r--glcpp/tests/046-if-1-elsif.c.expected11
-rw-r--r--glcpp/tests/047-if-elif-else.c11
-rw-r--r--glcpp/tests/047-if-elif-else.c.expected11
-rw-r--r--glcpp/tests/048-if-nested.c11
-rw-r--r--glcpp/tests/048-if-nested.c.expected11
-rw-r--r--glcpp/tests/049-if-expression-precedence.c5
-rw-r--r--glcpp/tests/049-if-expression-precedence.c.expected5
-rw-r--r--glcpp/tests/050-if-defined.c17
-rw-r--r--glcpp/tests/050-if-defined.c.expected17
-rw-r--r--glcpp/tests/051-if-relational.c35
-rw-r--r--glcpp/tests/051-if-relational.c.expected35
-rw-r--r--glcpp/tests/052-if-bitwise.c20
-rw-r--r--glcpp/tests/052-if-bitwise.c.expected20
-rw-r--r--glcpp/tests/053-if-divide-and-shift.c15
-rw-r--r--glcpp/tests/053-if-divide-and-shift.c.expected15
-rw-r--r--glcpp/tests/054-if-with-macros.c34
-rw-r--r--glcpp/tests/054-if-with-macros.c.expected34
-rw-r--r--glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c3
-rw-r--r--glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected3
-rw-r--r--glcpp/tests/056-macro-argument-with-comma.c4
-rw-r--r--glcpp/tests/056-macro-argument-with-comma.c.expected4
-rw-r--r--glcpp/tests/057-empty-arguments.c6
-rw-r--r--glcpp/tests/057-empty-arguments.c.expected6
-rw-r--r--glcpp/tests/058-token-pasting-empty-arguments.c5
-rw-r--r--glcpp/tests/058-token-pasting-empty-arguments.c.expected5
-rw-r--r--glcpp/tests/059-token-pasting-integer.c4
-rw-r--r--glcpp/tests/059-token-pasting-integer.c.expected4
-rw-r--r--glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c3
-rw-r--r--glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected3
-rw-r--r--glcpp/tests/061-define-chain-obj-to-func-multi.c5
-rw-r--r--glcpp/tests/061-define-chain-obj-to-func-multi.c.expected5
-rw-r--r--glcpp/tests/062-if-0-skips-garbage.c5
-rw-r--r--glcpp/tests/062-if-0-skips-garbage.c.expected5
-rw-r--r--glcpp/tests/063-comments.c20
-rw-r--r--glcpp/tests/063-comments.c.expected13
-rw-r--r--glcpp/tests/071-punctuator.c1
-rw-r--r--glcpp/tests/071-punctuator.c.expected1
-rw-r--r--glcpp/tests/072-token-pasting-same-line.c2
-rw-r--r--glcpp/tests/072-token-pasting-same-line.c.expected2
-rw-r--r--glcpp/tests/099-c99-example.c17
-rw-r--r--glcpp/tests/099-c99-example.c.expected16
-rwxr-xr-xglcpp/tests/glcpp-test7
-rw-r--r--glcpp/xtalloc.c99
147 files changed, 3508 insertions, 0 deletions
diff --git a/glcpp/.gitignore b/glcpp/.gitignore
new file mode 100644
index 0000000..077db8d
--- /dev/null
+++ b/glcpp/.gitignore
@@ -0,0 +1,7 @@
+glcpp
+glcpp-lex.c
+glcpp-parse.c
+glcpp-parse.h
+*.o
+*~
+tests/*.out
diff --git a/glcpp/Makefile b/glcpp/Makefile
new file mode 100644
index 0000000..3fb44ac
--- /dev/null
+++ b/glcpp/Makefile
@@ -0,0 +1,25 @@
+# Debug symbols by default, but let the user avoid that with something
+# like "make CFLAGS=-O2"
+CFLAGS = -g
+
+# But we use 'override' here so that "make CFLAGS=-O2" will still have
+# all the warnings enabled.
+override CFLAGS += -Wall -Wextra -Wwrite-strings -Wswitch-enum -Wno-unused
+
+glcpp: glcpp.o glcpp-lex.o glcpp-parse.o hash_table.o xtalloc.o
+ gcc -o $@ -ltalloc -lm $^
+
+%.c %.h: %.y
+ bison --debug --defines=$*.h --output=$*.c $^
+
+%.c: %.l
+ flex --prefix=glcpp_ --outfile=$@ $<
+
+glcpp-lex.c: glcpp-parse.h
+
+test: glcpp
+ @(cd tests; ./glcpp-test)
+
+clean:
+ rm -f glcpp glcpp-lex.c glcpp-parse.c *.o *~
+ rm -f tests/*.out tests/*~
diff --git a/glcpp/README b/glcpp/README
new file mode 100644
index 0000000..ab42a3f
--- /dev/null
+++ b/glcpp/README
@@ -0,0 +1,30 @@
+glcpp -- GLSL "C" preprocessor
+
+This is a simple preprocessor designed to provide the preprocessing
+needs of the GLSL language. The requirements for this preprocessor are
+specified in the GLSL 1.30 specification availble from:
+
+http://www.opengl.org/registry/doc/GLSLangSpec.Full.1.30.08.pdf
+
+This specification is not precise on some semantics, (for example,
+#define and #if), defining these merely "as is standard for C++
+preprocessors". To fill in these details, I've been using the C99
+standard (for which I had a convenient copy) as available from:
+
+http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
+
+Known limitations
+-----------------
+Macro invocations cannot include embedded newlines.
+
+The __LINE__, __FILE__, and __VERSION__ macros are not yet supported.
+
+The argument of the 'defined' operator cannot yet include enclosing
+parentheses.
+
+The #error, #pragma, #extension, #version, and #line macros are not
+yet supported.
+
+A file that ends with a function-like macro name as the last
+non-whitespace token will result in a parse error, (where it should be
+passed through as is). \ No newline at end of file
diff --git a/glcpp/glcpp-lex.l b/glcpp/glcpp-lex.l
new file mode 100644
index 0000000..0d9a754
--- /dev/null
+++ b/glcpp/glcpp-lex.l
@@ -0,0 +1,202 @@
+%{
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "glcpp.h"
+#include "glcpp-parse.h"
+%}
+
+%option reentrant noyywrap
+%option extra-type="glcpp_parser_t *"
+
+SPACE [[:space:]]
+NONSPACE [^[:space:]]
+NEWLINE [\n]
+HSPACE [ \t]
+HASH ^{HSPACE}*#{HSPACE}*
+IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]*
+PUNCTUATION [][(){}.&*~!/%<>^|;,=+-]
+OTHER [^][(){}.&*~!/%<>^|;,=#[:space:]+-]+
+
+DECIMAL_INTEGER [1-9][0-9]*[uU]?
+OCTAL_INTEGER 0[0-7]*[uU]?
+HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]?
+
+NON_STARS_THEN_STARS [^*]*[*]+
+
+%%
+
+ /* Single-line comments */
+"//"[^\n]+\n {
+ return NEWLINE;
+}
+
+ /* Multi-line comments */
+"/*"({NON_STARS_THEN_STARS}[^*/])*{NON_STARS_THEN_STARS}"/" {
+ if (yyextra->space_tokens)
+ return SPACE;
+}
+
+{HASH}if/.*\n {
+ yyextra->lexing_if = 1;
+ yyextra->space_tokens = 0;
+ return HASH_IF;
+}
+
+{HASH}elif/.*\n {
+ yyextra->lexing_if = 1;
+ yyextra->space_tokens = 0;
+ return HASH_ELIF;
+}
+
+{HASH}else/.*\n {
+ yyextra->space_tokens = 0;
+ return HASH_ELSE;
+}
+
+{HASH}endif/.*\n {
+ yyextra->space_tokens = 0;
+ return HASH_ENDIF;
+}
+
+ /* When skipping (due to an #if 0 or similar) consume anything
+ * up to a newline. We do this less priroty than any
+ * #if-related directive (#if, #elif, #else, #endif), but with
+ * more priority than any other directive or token to avoid
+ * any side-effects from skipped content.
+ *
+ * We use the lexing_if flag to avoid skipping any part of an
+ * if conditional expression. */
+[^\n]+/\n {
+ if (yyextra->lexing_if ||
+ yyextra->skip_stack == NULL ||
+ yyextra->skip_stack->type == SKIP_NO_SKIP)
+ {
+ REJECT;
+ }
+}
+
+{HASH}define{HSPACE}+/{IDENTIFIER}"(" {
+ yyextra->space_tokens = 0;
+ return HASH_DEFINE_FUNC;
+}
+
+{HASH}define {
+ yyextra->space_tokens = 0;
+ return HASH_DEFINE_OBJ;
+}
+
+{HASH}undef {
+ yyextra->space_tokens = 0;
+ return HASH_UNDEF;
+}
+
+{HASH} {
+ yyextra->space_tokens = 0;
+ return HASH;
+}
+
+{DECIMAL_INTEGER} {
+ yylval.str = xtalloc_strdup (yyextra, yytext);
+ return INTEGER_STRING;
+}
+
+{OCTAL_INTEGER} {
+ yylval.str = xtalloc_strdup (yyextra, yytext);
+ return INTEGER_STRING;
+}
+
+{HEXADECIMAL_INTEGER} {
+ yylval.str = xtalloc_strdup (yyextra, yytext);
+ return INTEGER_STRING;
+}
+
+"<<" {
+ return LEFT_SHIFT;
+}
+
+">>" {
+ return RIGHT_SHIFT;
+}
+
+"<=" {
+ return LESS_OR_EQUAL;
+}
+
+">=" {
+ return GREATER_OR_EQUAL;
+}
+
+"==" {
+ return EQUAL;
+}
+
+"!=" {
+ return NOT_EQUAL;
+}
+
+"&&" {
+ return AND;
+}
+
+"||" {
+ return OR;
+}
+
+"##" {
+ return PASTE;
+}
+
+"defined" {
+ return DEFINED;
+}
+
+{IDENTIFIER} {
+ yylval.str = xtalloc_strdup (yyextra, yytext);
+ return IDENTIFIER;
+}
+
+{PUNCTUATION} {
+ return yytext[0];
+}
+
+{OTHER}+ {
+ yylval.str = xtalloc_strdup (yyextra, yytext);
+ return OTHER;
+}
+
+{HSPACE}+ {
+ if (yyextra->space_tokens) {
+ return SPACE;
+ }
+}
+
+\n {
+ yyextra->lexing_if = 0;
+ return NEWLINE;
+}
+
+%%
diff --git a/glcpp/glcpp-parse.y b/glcpp/glcpp-parse.y
new file mode 100644
index 0000000..807cf59
--- /dev/null
+++ b/glcpp/glcpp-parse.y
@@ -0,0 +1,1602 @@
+%{
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <inttypes.h>
+
+#include "glcpp.h"
+
+static void
+yyerror (void *scanner, const char *error);
+
+static void
+_define_object_macro (glcpp_parser_t *parser,
+ const char *macro,
+ token_list_t *replacements);
+
+static void
+_define_function_macro (glcpp_parser_t *parser,
+ const char *macro,
+ string_list_t *parameters,
+ token_list_t *replacements);
+
+static string_list_t *
+_string_list_create (void *ctx);
+
+static void
+_string_list_append_item (string_list_t *list, const char *str);
+
+static void
+_string_list_append_list (string_list_t *list, string_list_t *tail);
+
+static int
+_string_list_contains (string_list_t *list, const char *member, int *index);
+
+static int
+_string_list_length (string_list_t *list);
+
+static argument_list_t *
+_argument_list_create (void *ctx);
+
+static void
+_argument_list_append (argument_list_t *list, token_list_t *argument);
+
+static int
+_argument_list_length (argument_list_t *list);
+
+static token_list_t *
+_argument_list_member_at (argument_list_t *list, int index);
+
+/* Note: This function talloc_steal()s the str pointer. */
+static token_t *
+_token_create_str (void *ctx, int type, char *str);
+
+static token_t *
+_token_create_ival (void *ctx, int type, int ival);
+
+static token_list_t *
+_token_list_create (void *ctx);
+
+/* Note: This function adds a talloc_reference() to token.
+ *
+ * You may want to talloc_unlink any current reference if you no
+ * longer need it. */
+static void
+_token_list_append (token_list_t *list, token_t *token);
+
+static void
+_token_list_append_list (token_list_t *list, token_list_t *tail);
+
+static int
+_token_list_length (token_list_t *list);
+
+static active_list_t *
+_active_list_push (active_list_t *list,
+ const char *identifier,
+ token_node_t *marker);
+
+static active_list_t *
+_active_list_pop (active_list_t *list);
+
+int
+_active_list_contains (active_list_t *list, const char *identifier);
+
+static void
+_glcpp_parser_evaluate_defined (glcpp_parser_t *parser,
+ token_list_t *list);
+
+static void
+_glcpp_parser_expand_token_list (glcpp_parser_t *parser,
+ token_list_t *list);
+
+static void
+_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
+ token_list_t *list);
+
+static void
+_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, int condition);
+
+static void
+_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, const char *type,
+ int condition);
+
+static void
+_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser);
+
+#define yylex glcpp_parser_lex
+
+static int
+glcpp_parser_lex (glcpp_parser_t *parser);
+
+static void
+glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list);
+
+%}
+
+%parse-param {glcpp_parser_t *parser}
+%lex-param {glcpp_parser_t *parser}
+
+%token COMMA_FINAL DEFINED ELIF_EXPANDED HASH HASH_DEFINE_FUNC HASH_DEFINE_OBJ HASH_ELIF HASH_ELSE HASH_ENDIF HASH_IF HASH_IFDEF HASH_IFNDEF HASH_UNDEF IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING NEWLINE OTHER PLACEHOLDER SPACE
+%token PASTE
+%type <ival> expression INTEGER operator SPACE
+%type <str> IDENTIFIER INTEGER_STRING OTHER
+%type <string_list> identifier_list
+%type <token> preprocessing_token
+%type <token_list> pp_tokens replacement_list text_line
+%left OR
+%left AND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOT_EQUAL
+%left '<' '>' LESS_OR_EQUAL GREATER_OR_EQUAL
+%left LEFT_SHIFT RIGHT_SHIFT
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY
+
+%%
+
+input:
+ /* empty */
+| input line
+;
+
+line:
+ control_line {
+ printf ("\n");
+ }
+| text_line {
+ _glcpp_parser_print_expanded_token_list (parser, $1);
+ printf ("\n");
+ talloc_free ($1);
+ }
+| expanded_line
+| HASH non_directive
+;
+
+expanded_line:
+ IF_EXPANDED expression NEWLINE {
+ _glcpp_parser_skip_stack_push_if (parser, $2);
+ }
+| ELIF_EXPANDED expression NEWLINE {
+ _glcpp_parser_skip_stack_change_if (parser, "elif", $2);
+ }
+;
+
+control_line:
+ HASH_DEFINE_OBJ IDENTIFIER replacement_list NEWLINE {
+ _define_object_macro (parser, $2, $3);
+ }
+| HASH_DEFINE_FUNC IDENTIFIER '(' ')' replacement_list NEWLINE {
+ _define_function_macro (parser, $2, NULL, $5);
+ }
+| HASH_DEFINE_FUNC IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE {
+ _define_function_macro (parser, $2, $4, $6);
+ }
+| HASH_UNDEF IDENTIFIER NEWLINE {
+ macro_t *macro = hash_table_find (parser->defines, $2);
+ if (macro) {
+ /* XXX: Need hash table to support a real way
+ * to remove an element rather than prefixing
+ * a new node with data of NULL like this. */
+ hash_table_insert (parser->defines, NULL, $2);
+ talloc_free (macro);
+ }
+ talloc_free ($2);
+ }
+| HASH_IF pp_tokens NEWLINE {
+ token_list_t *expanded;
+ token_t *token;
+
+ expanded = _token_list_create (parser);
+ token = _token_create_ival (parser, IF_EXPANDED, IF_EXPANDED);
+ _token_list_append (expanded, token);
+ talloc_unlink (parser, token);
+ _glcpp_parser_evaluate_defined (parser, $2);
+ _glcpp_parser_expand_token_list (parser, $2);
+ _token_list_append_list (expanded, $2);
+ glcpp_parser_lex_from (parser, expanded);
+ }
+| HASH_IFDEF IDENTIFIER NEWLINE {
+ macro_t *macro = hash_table_find (parser->defines, $2);
+ talloc_free ($2);
+ _glcpp_parser_skip_stack_push_if (parser, macro != NULL);
+ }
+| HASH_IFNDEF IDENTIFIER NEWLINE {
+ macro_t *macro = hash_table_find (parser->defines, $2);
+ talloc_free ($2);
+ _glcpp_parser_skip_stack_push_if (parser, macro == NULL);
+ }
+| HASH_ELIF pp_tokens NEWLINE {
+ token_list_t *expanded;
+ token_t *token;
+
+ expanded = _token_list_create (parser);
+ token = _token_create_ival (parser, ELIF_EXPANDED, ELIF_EXPANDED);
+ _token_list_append (expanded, token);
+ talloc_unlink (parser, token);
+ _glcpp_parser_evaluate_defined (parser, $2);
+ _glcpp_parser_expand_token_list (parser, $2);
+ _token_list_append_list (expanded, $2);
+ glcpp_parser_lex_from (parser, expanded);
+ }
+| HASH_ELSE NEWLINE {
+ _glcpp_parser_skip_stack_change_if (parser, "else", 1);
+ }
+| HASH_ENDIF NEWLINE {
+ _glcpp_parser_skip_stack_pop (parser);
+ }
+| HASH NEWLINE
+;
+
+expression:
+ INTEGER_STRING {
+ if (strlen ($1) >= 3 && strncmp ($1, "0x", 2) == 0) {
+ $$ = strtoll ($1 + 2, NULL, 16);
+ } else if ($1[0] == '0') {
+ $$ = strtoll ($1, NULL, 8);
+ } else {
+ $$ = strtoll ($1, NULL, 10);
+ }
+ }
+| INTEGER {
+ $$ = $1;
+ }
+| expression OR expression {
+ $$ = $1 || $3;
+ }
+| expression AND expression {
+ $$ = $1 && $3;
+ }
+| expression '|' expression {
+ $$ = $1 | $3;
+ }
+| expression '^' expression {
+ $$ = $1 ^ $3;
+ }
+| expression '&' expression {
+ $$ = $1 & $3;
+ }
+| expression NOT_EQUAL expression {
+ $$ = $1 != $3;
+ }
+| expression EQUAL expression {
+ $$ = $1 == $3;
+ }
+| expression GREATER_OR_EQUAL expression {
+ $$ = $1 >= $3;
+ }
+| expression LESS_OR_EQUAL expression {
+ $$ = $1 <= $3;
+ }
+| expression '>' expression {
+ $$ = $1 > $3;
+ }
+| expression '<' expression {
+ $$ = $1 < $3;
+ }
+| expression RIGHT_SHIFT expression {
+ $$ = $1 >> $3;
+ }
+| expression LEFT_SHIFT expression {
+ $$ = $1 << $3;
+ }
+| expression '-' expression {
+ $$ = $1 - $3;
+ }
+| expression '+' expression {
+ $$ = $1 + $3;
+ }
+| expression '%' expression {
+ $$ = $1 % $3;
+ }
+| expression '/' expression {
+ $$ = $1 / $3;
+ }
+| expression '*' expression {
+ $$ = $1 * $3;
+ }
+| '!' expression %prec UNARY {
+ $$ = ! $2;
+ }
+| '~' expression %prec UNARY {
+ $$ = ~ $2;
+ }
+| '-' expression %prec UNARY {
+ $$ = - $2;
+ }
+| '+' expression %prec UNARY {
+ $$ = + $2;
+ }
+| '(' expression ')' {
+ $$ = $2;
+ }
+;
+
+identifier_list:
+ IDENTIFIER {
+ $$ = _string_list_create (parser);
+ _string_list_append_item ($$, $1);
+ talloc_steal ($$, $1);
+ }
+| identifier_list ',' IDENTIFIER {
+ $$ = $1;
+ _string_list_append_item ($$, $3);
+ talloc_steal ($$, $3);
+ }
+;
+
+text_line:
+ NEWLINE { $$ = NULL; }
+| pp_tokens NEWLINE
+;
+
+non_directive:
+ pp_tokens NEWLINE
+;
+
+replacement_list:
+ /* empty */ { $$ = NULL; }
+| pp_tokens
+;
+
+pp_tokens:
+ preprocessing_token {
+ parser->space_tokens = 1;
+ $$ = _token_list_create (parser);
+ _token_list_append ($$, $1);
+ talloc_unlink (parser, $1);
+ }
+| pp_tokens preprocessing_token {
+ $$ = $1;
+ _token_list_append ($$, $2);
+ talloc_unlink (parser, $2);
+ }
+;
+
+preprocessing_token:
+ IDENTIFIER {
+ $$ = _token_create_str (parser, IDENTIFIER, $1);
+ }
+| INTEGER_STRING {
+ $$ = _token_create_str (parser, INTEGER_STRING, $1);
+ }
+| operator {
+ $$ = _token_create_ival (parser, $1, $1);
+ }
+| OTHER {
+ $$ = _token_create_str (parser, OTHER, $1);
+ }
+| SPACE {
+ $$ = _token_create_ival (parser, SPACE, SPACE);
+ }
+;
+
+operator:
+ '[' { $$ = '['; }
+| ']' { $$ = ']'; }
+| '(' { $$ = '('; }
+| ')' { $$ = ')'; }
+| '{' { $$ = '{'; }
+| '}' { $$ = '}'; }
+| '.' { $$ = '.'; }
+| '&' { $$ = '&'; }
+| '*' { $$ = '*'; }
+| '+' { $$ = '+'; }
+| '-' { $$ = '-'; }
+| '~' { $$ = '~'; }
+| '!' { $$ = '!'; }
+| '/' { $$ = '/'; }
+| '%' { $$ = '%'; }
+| LEFT_SHIFT { $$ = LEFT_SHIFT; }
+| RIGHT_SHIFT { $$ = RIGHT_SHIFT; }
+| '<' { $$ = '<'; }
+| '>' { $$ = '>'; }
+| LESS_OR_EQUAL { $$ = LESS_OR_EQUAL; }
+| GREATER_OR_EQUAL { $$ = GREATER_OR_EQUAL; }
+| EQUAL { $$ = EQUAL; }
+| NOT_EQUAL { $$ = NOT_EQUAL; }
+| '^' { $$ = '^'; }
+| '|' { $$ = '|'; }
+| AND { $$ = AND; }
+| OR { $$ = OR; }
+| ';' { $$ = ';'; }
+| ',' { $$ = ','; }
+| '=' { $$ = '='; }
+| PASTE { $$ = PASTE; }
+| DEFINED { $$ = DEFINED; }
+;
+
+%%
+
+string_list_t *
+_string_list_create (void *ctx)
+{
+ string_list_t *list;
+
+ list = xtalloc (ctx, string_list_t);
+ list->head = NULL;
+ list->tail = NULL;
+
+ return list;
+}
+
+void
+_string_list_append_list (string_list_t *list, string_list_t *tail)
+{
+ if (list->head == NULL) {
+ list->head = tail->head;
+ } else {
+ list->tail->next = tail->head;
+ }
+
+ list->tail = tail->tail;
+}
+
+void
+_string_list_append_item (string_list_t *list, const char *str)
+{
+ string_node_t *node;
+
+ node = xtalloc (list, string_node_t);
+ node->str = xtalloc_strdup (node, str);
+
+ node->next = NULL;
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+}
+
+int
+_string_list_contains (string_list_t *list, const char *member, int *index)
+{
+ string_node_t *node;
+ int i;
+
+ if (list == NULL)
+ return 0;
+
+ for (i = 0, node = list->head; node; i++, node = node->next) {
+ if (strcmp (node->str, member) == 0) {
+ if (index)
+ *index = i;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+_string_list_length (string_list_t *list)
+{
+ int length = 0;
+ string_node_t *node;
+
+ if (list == NULL)
+ return 0;
+
+ for (node = list->head; node; node = node->next)
+ length++;
+
+ return length;
+}
+
+argument_list_t *
+_argument_list_create (void *ctx)
+{
+ argument_list_t *list;
+
+ list = xtalloc (ctx, argument_list_t);
+ list->head = NULL;
+ list->tail = NULL;
+
+ return list;
+}
+
+void
+_argument_list_append (argument_list_t *list, token_list_t *argument)
+{
+ argument_node_t *node;
+
+ node = xtalloc (list, argument_node_t);
+ node->argument = argument;
+
+ node->next = NULL;
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+}
+
+int
+_argument_list_length (argument_list_t *list)
+{
+ int length = 0;
+ argument_node_t *node;
+
+ if (list == NULL)
+ return 0;
+
+ for (node = list->head; node; node = node->next)
+ length++;
+
+ return length;
+}
+
+token_list_t *
+_argument_list_member_at (argument_list_t *list, int index)
+{
+ argument_node_t *node;
+ int i;
+
+ if (list == NULL)
+ return NULL;
+
+ node = list->head;
+ for (i = 0; i < index; i++) {
+ node = node->next;
+ if (node == NULL)
+ break;
+ }
+
+ if (node)
+ return node->argument;
+
+ return NULL;
+}
+
+/* Note: This function talloc_steal()s the str pointer. */
+token_t *
+_token_create_str (void *ctx, int type, char *str)
+{
+ token_t *token;
+
+ token = xtalloc (ctx, token_t);
+ token->type = type;
+ token->value.str = talloc_steal (token, str);
+
+ return token;
+}
+
+token_t *
+_token_create_ival (void *ctx, int type, int ival)
+{
+ token_t *token;
+
+ token = xtalloc (ctx, token_t);
+ token->type = type;
+ token->value.ival = ival;
+
+ return token;
+}
+
+token_list_t *
+_token_list_create (void *ctx)
+{
+ token_list_t *list;
+
+ list = xtalloc (ctx, token_list_t);
+ list->head = NULL;
+ list->tail = NULL;
+ list->non_space_tail = NULL;
+
+ return list;
+}
+
+void
+_token_list_append (token_list_t *list, token_t *token)
+{
+ token_node_t *node;
+
+ node = xtalloc (list, token_node_t);
+ node->token = xtalloc_reference (list, token);
+
+ node->next = NULL;
+
+ if (list->head == NULL) {
+ list->head = node;
+ } else {
+ list->tail->next = node;
+ }
+
+ list->tail = node;
+ if (token->type != SPACE)
+ list->non_space_tail = node;
+}
+
+void
+_token_list_append_list (token_list_t *list, token_list_t *tail)
+{
+ if (tail == NULL || tail->head == NULL)
+ return;
+
+ if (list->head == NULL) {
+ list->head = tail->head;
+ } else {
+ list->tail->next = tail->head;
+ }
+
+ list->tail = tail->tail;
+ list->non_space_tail = tail->non_space_tail;
+}
+
+token_list_t *
+_token_list_copy (void *ctx, token_list_t *other)
+{
+ token_list_t *copy;
+ token_node_t *node;
+
+ if (other == NULL)
+ return NULL;
+
+ copy = _token_list_create (ctx);
+ for (node = other->head; node; node = node->next)
+ _token_list_append (copy, node->token);
+
+ return copy;
+}
+
+void
+_token_list_trim_trailing_space (token_list_t *list)
+{
+ token_node_t *tail, *next;
+
+ if (list->non_space_tail) {
+ tail = list->non_space_tail->next;
+ list->non_space_tail->next = NULL;
+ list->tail = list->non_space_tail;
+
+ while (tail) {
+ next = tail->next;
+ talloc_free (tail);
+ tail = next;
+ }
+ }
+}
+
+static int
+_token_list_length (token_list_t *list)
+{
+ int length = 0;
+ token_node_t *node;
+
+ if (list == NULL)
+ return 0;
+
+ for (node = list->head; node; node = node->next)
+ length++;
+
+ return length;
+}
+
+static void
+_token_print (token_t *token)
+{
+ if (token->type < 256) {
+ printf ("%c", token->type);
+ return;
+ }
+
+ switch (token->type) {
+ case INTEGER:
+ printf ("%" PRIxMAX, token->value.ival);
+ break;
+ case IDENTIFIER:
+ case INTEGER_STRING:
+ case OTHER:
+ printf ("%s", token->value.str);
+ break;
+ case SPACE:
+ printf (" ");
+ break;
+ case LEFT_SHIFT:
+ printf ("<<");
+ break;
+ case RIGHT_SHIFT:
+ printf (">>");
+ break;
+ case LESS_OR_EQUAL:
+ printf ("<=");
+ break;
+ case GREATER_OR_EQUAL:
+ printf (">=");
+ break;
+ case EQUAL:
+ printf ("==");
+ break;
+ case NOT_EQUAL:
+ printf ("!=");
+ break;
+ case AND:
+ printf ("&&");
+ break;
+ case OR:
+ printf ("||");
+ break;
+ case PASTE:
+ printf ("##");
+ break;
+ case COMMA_FINAL:
+ printf (",");
+ break;
+ case PLACEHOLDER:
+ /* Nothing to print. */
+ break;
+ default:
+ fprintf (stderr, "Error: Don't know how to print token type %d\n", token->type);
+ break;
+ }
+}
+
+/* Return a new token (talloc()ed off of 'token') formed by pasting
+ * 'token' and 'other'. Note that this function may return 'token' or
+ * 'other' directly rather than allocating anything new.
+ *
+ * Caution: Only very cursory error-checking is performed to see if
+ * the final result is a valid single token. */
+static token_t *
+_token_paste (token_t *token, token_t *other)
+{
+ /* Pasting a placeholder onto anything makes no change. */
+ if (other->type == PLACEHOLDER)
+ return token;
+
+ /* When 'token' is a placeholder, just return 'other'. */
+ if (token->type == PLACEHOLDER)
+ return other;
+
+ /* A very few single-character punctuators can be combined
+ * with another to form a multi-character punctuator. */
+ switch (token->type) {
+ case '<':
+ if (other->type == '<')
+ return _token_create_ival (token, LEFT_SHIFT, LEFT_SHIFT);
+ else if (other->type == '=')
+ return _token_create_ival (token, LESS_OR_EQUAL, LESS_OR_EQUAL);
+ break;
+ case '>':
+ if (other->type == '>')
+ return _token_create_ival (token, RIGHT_SHIFT, RIGHT_SHIFT);
+ else if (other->type == '=')
+ return _token_create_ival (token, GREATER_OR_EQUAL, GREATER_OR_EQUAL);
+ break;
+ case '=':
+ if (other->type == '=')
+ return _token_create_ival (token, EQUAL, EQUAL);
+ break;
+ case '!':
+ if (other->type == '=')
+ return _token_create_ival (token, NOT_EQUAL, NOT_EQUAL);
+ break;
+ case '&':
+ if (other->type == '&')
+ return _token_create_ival (token, AND, AND);
+ break;
+ case '|':
+ if (other->type == '|')
+ return _token_create_ival (token, OR, OR);
+ break;
+ }
+
+ /* Two string-valued tokens can usually just be mashed
+ * together.
+ *
+ * XXX: This isn't actually legitimate. Several things here
+ * should result in a diagnostic since the result cannot be a
+ * valid, single pre-processing token. For example, pasting
+ * "123" and "abc" is not legal, but we don't catch that
+ * here. */
+ if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING) &&
+ (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING))
+ {
+ char *str;
+
+ str = xtalloc_asprintf (token, "%s%s",
+ token->value.str, other->value.str);
+ return _token_create_str (token, token->type, str);
+ }
+
+ printf ("Error: Pasting \"");
+ _token_print (token);
+ printf ("\" and \"");
+ _token_print (other);
+ printf ("\" does not give a valid preprocessing token.\n");
+
+ return token;
+}
+
+static void
+_token_list_print (token_list_t *list)
+{
+ token_node_t *node;
+
+ if (list == NULL)
+ return;
+
+ for (node = list->head; node; node = node->next)
+ _token_print (node->token);
+}
+
+void
+yyerror (void *scanner, const char *error)
+{
+ fprintf (stderr, "Parse error: %s\n", error);
+}
+
+glcpp_parser_t *
+glcpp_parser_create (void)
+{
+ glcpp_parser_t *parser;
+
+ parser = xtalloc (NULL, glcpp_parser_t);
+
+ glcpp_lex_init_extra (parser, &parser->scanner);
+ parser->defines = hash_table_ctor (32, hash_table_string_hash,
+ hash_table_string_compare);
+ parser->active = NULL;
+ parser->lexing_if = 0;
+ parser->space_tokens = 1;
+ parser->newline_as_space = 0;
+ parser->in_control_line = 0;
+ parser->paren_count = 0;
+
+ parser->skip_stack = NULL;
+
+ parser->lex_from_list = NULL;
+ parser->lex_from_node = NULL;
+
+ return parser;
+}
+
+int
+glcpp_parser_parse (glcpp_parser_t *parser)
+{
+ return yyparse (parser);
+}
+
+void
+glcpp_parser_destroy (glcpp_parser_t *parser)
+{
+ if (parser->skip_stack)
+ fprintf (stderr, "Error: Unterminated #if\n");
+ glcpp_lex_destroy (parser->scanner);
+ hash_table_dtor (parser->defines);
+ talloc_free (parser);
+}
+
+/* Replace any occurences of DEFINED tokens in 'list' with either a
+ * '0' or '1' INTEGER token depending on whether the next token in the
+ * list is defined or not. */
+static void
+_glcpp_parser_evaluate_defined (glcpp_parser_t *parser,
+ token_list_t *list)
+{
+ token_node_t *node, *next;
+ macro_t *macro;
+
+ if (list == NULL)
+ return;
+
+ for (node = list->head; node; node = node->next) {
+ if (node->token->type != DEFINED)
+ continue;
+ next = node->next;
+ while (next && next->token->type == SPACE)
+ next = next->next;
+ if (next == NULL || next->token->type != IDENTIFIER) {
+ fprintf (stderr, "Error: operator \"defined\" requires an identifier\n");
+ exit (1);
+ }
+ macro = hash_table_find (parser->defines,
+ next->token->value.str);
+
+ node->token->type = INTEGER;
+ node->token->value.ival = (macro != NULL);
+ node->next = next->next;
+ }
+}
+
+typedef enum function_status
+{
+ FUNCTION_STATUS_SUCCESS,
+ FUNCTION_NOT_A_FUNCTION,
+ FUNCTION_UNBALANCED_PARENTHESES
+} function_status_t;
+
+/* Find a set of function-like macro arguments by looking for a
+ * balanced set of parentheses.
+ *
+ * When called, 'node' should be the opening-parenthesis token, (or
+ * perhaps preceeding SPACE tokens). Upon successful return *last will
+ * be the last consumed node, (corresponding to the closing right
+ * parenthesis).
+ *
+ * Return values:
+ *
+ * FUNCTION_STATUS_SUCCESS:
+ *
+ * Successfully parsed a set of function arguments.
+ *
+ * FUNCTION_NOT_A_FUNCTION:
+ *
+ * Macro name not followed by a '('. This is not an error, but
+ * simply that the macro name should be treated as a non-macro.
+ *
+ * FUNCTION_UNBALANCED_PARENTHESES
+ *
+ * Macro name is not followed by a balanced set of parentheses.
+ */
+static function_status_t
+_arguments_parse (argument_list_t *arguments,
+ token_node_t *node,
+ token_node_t **last)
+{
+ token_list_t *argument;
+ int paren_count;
+
+ node = node->next;
+
+ /* Ignore whitespace before first parenthesis. */
+ while (node && node->token->type == SPACE)
+ node = node->next;
+
+ if (node == NULL || node->token->type != '(')
+ return FUNCTION_NOT_A_FUNCTION;
+
+ node = node->next;
+
+ argument = _token_list_create (arguments);
+ _argument_list_append (arguments, argument);
+
+ for (paren_count = 1; node; node = node->next) {
+ if (node->token->type == '(')
+ {
+ paren_count++;
+ }
+ else if (node->token->type == ')')
+ {
+ paren_count--;
+ if (paren_count == 0)
+ break;
+ }
+
+ if (node->token->type == ',' &&
+ paren_count == 1)
+ {
+ _token_list_trim_trailing_space (argument);
+ argument = _token_list_create (arguments);
+ _argument_list_append (arguments, argument);
+ }
+ else {
+ if (argument->head == NULL) {
+ /* Don't treat initial whitespace as
+ * part of the arguement. */
+ if (node->token->type == SPACE)
+ continue;
+ }
+ _token_list_append (argument, node->token);
+ }
+ }
+
+ if (paren_count)
+ return FUNCTION_UNBALANCED_PARENTHESES;
+
+ *last = node;
+
+ return FUNCTION_STATUS_SUCCESS;
+}
+
+/* This is a helper function that's essentially part of the
+ * implementation of _glcpp_parser_expand_node. It shouldn't be called
+ * except for by that function.
+ *
+ * Returns NULL if node is a simple token with no expansion, (that is,
+ * although 'node' corresponds to an identifier defined as a
+ * function-like macro, it is not followed with a parenthesized
+ * argument list).
+ *
+ * Compute the complete expansion of node (which is a function-like
+ * macro) and subsequent nodes which are arguments.
+ *
+ * Returns the token list that results from the expansion and sets
+ * *last to the last node in the list that was consumed by the
+ * expansion. Specificallty, *last will be set as follows: as the
+ * token of the closing right parenthesis.
+ */
+static token_list_t *
+_glcpp_parser_expand_function (glcpp_parser_t *parser,
+ token_node_t *node,
+ token_node_t **last)
+
+{
+ macro_t *macro;
+ const char *identifier;
+ argument_list_t *arguments;
+ function_status_t status;
+ token_list_t *substituted;
+ int parameter_index;
+
+ identifier = node->token->value.str;
+
+ macro = hash_table_find (parser->defines, identifier);
+
+ assert (macro->is_function);
+
+ arguments = _argument_list_create (parser);
+ status = _arguments_parse (arguments, node, last);
+
+ switch (status) {
+ case FUNCTION_STATUS_SUCCESS:
+ break;
+ case FUNCTION_NOT_A_FUNCTION:
+ return NULL;
+ case FUNCTION_UNBALANCED_PARENTHESES:
+ fprintf (stderr, "Error: Macro %s call has unbalanced parentheses\n",
+ identifier);
+ exit (1);
+ return NULL;
+ }
+
+ if (macro->replacements == NULL) {
+ talloc_free (arguments);
+ return _token_list_create (parser);
+ }
+
+ if (! ((_argument_list_length (arguments) ==
+ _string_list_length (macro->parameters)) ||
+ (_string_list_length (macro->parameters) == 0 &&
+ _argument_list_length (arguments) == 1 &&
+ arguments->head->argument->head == NULL)))
+ {
+ fprintf (stderr,
+ "Error: macro %s invoked with %d arguments (expected %d)\n",
+ identifier,
+ _argument_list_length (arguments),
+ _string_list_length (macro->parameters));
+ return NULL;
+ }
+
+ /* Perform argument substitution on the replacement list. */
+ substituted = _token_list_create (arguments);
+
+ for (node = macro->replacements->head; node; node = node->next)
+ {
+ if (node->token->type == IDENTIFIER &&
+ _string_list_contains (macro->parameters,
+ node->token->value.str,
+ &parameter_index))
+ {
+ token_list_t *argument;
+ argument = _argument_list_member_at (arguments,
+ parameter_index);
+ /* Before substituting, we expand the argument
+ * tokens, or append a placeholder token for
+ * an empty argument. */
+ if (argument->head) {
+ _glcpp_parser_expand_token_list (parser,
+ argument);
+ _token_list_append_list (substituted, argument);
+ } else {
+ token_t *new_token;
+
+ new_token = _token_create_ival (substituted,
+ PLACEHOLDER,
+ PLACEHOLDER);
+ _token_list_append (substituted, new_token);
+ }
+ } else {
+ _token_list_append (substituted, node->token);
+ }
+ }
+
+ /* After argument substitution, and before further expansion
+ * below, implement token pasting. */
+
+ _token_list_trim_trailing_space (substituted);
+
+ node = substituted->head;
+ while (node)
+ {
+ token_node_t *next_non_space;
+
+ /* Look ahead for a PASTE token, skipping space. */
+ next_non_space = node->next;
+ while (next_non_space && next_non_space->token->type == SPACE)
+ next_non_space = next_non_space->next;
+
+ if (next_non_space == NULL)
+ break;
+
+ if (next_non_space->token->type != PASTE) {
+ node = next_non_space;
+ continue;
+ }
+
+ /* Now find the next non-space token after the PASTE. */
+ next_non_space = next_non_space->next;
+ while (next_non_space && next_non_space->token->type == SPACE)
+ next_non_space = next_non_space->next;
+
+ if (next_non_space == NULL) {
+ fprintf (stderr, "Error: '##' cannot appear at either end of a macro expansion\n");
+ return NULL;
+ }
+
+ node->token = _token_paste (node->token, next_non_space->token);
+ node->next = next_non_space->next;
+ if (next_non_space == substituted->tail)
+ substituted->tail = node;
+
+ node = node->next;
+ }
+
+ substituted->non_space_tail = substituted->tail;
+
+ return substituted;
+}
+
+/* Compute the complete expansion of node, (and subsequent nodes after
+ * 'node' in the case that 'node' is a function-like macro and
+ * subsequent nodes are arguments).
+ *
+ * Returns NULL if node is a simple token with no expansion.
+ *
+ * Otherwise, returns the token list that results from the expansion
+ * and sets *last to the last node in the list that was consumed by
+ * the expansion. Specificallty, *last will be set as follows:
+ *
+ * As 'node' in the case of object-like macro expansion.
+ *
+ * As the token of the closing right parenthesis in the case of
+ * function-like macro expansion.
+ */
+static token_list_t *
+_glcpp_parser_expand_node (glcpp_parser_t *parser,
+ token_node_t *node,
+ token_node_t **last)
+{
+ token_t *token = node->token;
+ const char *identifier;
+ macro_t *macro;
+
+ /* We only expand identifiers */
+ if (token->type != IDENTIFIER) {
+ /* We change any COMMA into a COMMA_FINAL to prevent
+ * it being mistaken for an argument separator
+ * later. */
+ if (token->type == ',') {
+ token->type = COMMA_FINAL;
+ token->value.ival = COMMA_FINAL;
+ }
+
+ return NULL;
+ }
+
+ /* Look up this identifier in the hash table. */
+ identifier = token->value.str;
+ macro = hash_table_find (parser->defines, identifier);
+
+ /* Not a macro, so no expansion needed. */
+ if (macro == NULL)
+ return NULL;
+
+ /* Finally, don't expand this macro if we're already actively
+ * expanding it, (to avoid infinite recursion). */
+ if (_active_list_contains (parser->active, identifier)) {
+ /* We change the token type here from IDENTIFIER to
+ * OTHER to prevent any future expansion of this
+ * unexpanded token. */
+ char *str;
+ token_list_t *expansion;
+ token_t *final;
+
+ str = xtalloc_strdup (parser, token->value.str);
+ final = _token_create_str (parser, OTHER, str);
+ expansion = _token_list_create (parser);
+ _token_list_append (expansion, final);
+ *last = node;
+ return expansion;
+ }
+
+ if (! macro->is_function)
+ {
+ *last = node;
+
+ if (macro->replacements == NULL)
+ return _token_list_create (parser);
+
+ return _token_list_copy (parser, macro->replacements);
+ }
+
+ return _glcpp_parser_expand_function (parser, node, last);
+}
+
+/* Push a new identifier onto the active list, returning the new list.
+ *
+ * Here, 'marker' is the token node that appears in the list after the
+ * expansion of 'identifier'. That is, when the list iterator begins
+ * examinging 'marker', then it is time to pop this node from the
+ * active stack.
+ */
+active_list_t *
+_active_list_push (active_list_t *list,
+ const char *identifier,
+ token_node_t *marker)
+{
+ active_list_t *node;
+
+ node = xtalloc (list, active_list_t);
+ node->identifier = xtalloc_strdup (node, identifier);
+ node->marker = marker;
+ node->next = list;
+
+ return node;
+}
+
+active_list_t *
+_active_list_pop (active_list_t *list)
+{
+ active_list_t *node = list;
+
+ if (node == NULL)
+ return NULL;
+
+ node = list->next;
+ talloc_free (list);
+
+ return node;
+}
+
+int
+_active_list_contains (active_list_t *list, const char *identifier)
+{
+ active_list_t *node;
+
+ if (list == NULL)
+ return 0;
+
+ for (node = list; node; node = node->next)
+ if (strcmp (node->identifier, identifier) == 0)
+ return 1;
+
+ return 0;
+}
+
+/* Walk over the token list replacing nodes with their expansion.
+ * Whenever nodes are expanded the walking will walk over the new
+ * nodes, continuing to expand as necessary. The results are placed in
+ * 'list' itself;
+ */
+static void
+_glcpp_parser_expand_token_list (glcpp_parser_t *parser,
+ token_list_t *list)
+{
+ token_node_t *node_prev;
+ token_node_t *node, *last;
+ token_list_t *expansion;
+
+ if (list == NULL)
+ return;
+
+ _token_list_trim_trailing_space (list);
+
+ node_prev = NULL;
+ node = list->head;
+
+ while (node) {
+
+ while (parser->active && parser->active->marker == node)
+ parser->active = _active_list_pop (parser->active);
+
+ /* Find the expansion for node, which will replace all
+ * nodes from node to last, inclusive. */
+ expansion = _glcpp_parser_expand_node (parser, node, &last);
+ if (expansion) {
+ token_node_t *n;
+
+ for (n = node; n != last->next; n = n->next)
+ while (parser->active &&
+ parser->active->marker == n)
+ {
+ parser->active = _active_list_pop (parser->active);
+ }
+
+ parser->active = _active_list_push (parser->active,
+ node->token->value.str,
+ last->next);
+
+ /* Splice expansion into list, supporting a
+ * simple deletion if the expansion is
+ * empty. */
+ if (expansion->head) {
+ if (node_prev)
+ node_prev->next = expansion->head;
+ else
+ list->head = expansion->head;
+ expansion->tail->next = last->next;
+ if (last == list->tail)
+ list->tail = expansion->tail;
+ } else {
+ if (node_prev)
+ node_prev->next = last->next;
+ else
+ list->head = last->next;
+ if (last == list->tail)
+ list->tail == NULL;
+ }
+ } else {
+ node_prev = node;
+ }
+ node = node_prev ? node_prev->next : list->head;
+ }
+
+ while (parser->active)
+ parser->active = _active_list_pop (parser->active);
+
+ list->non_space_tail = list->tail;
+}
+
+void
+_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser,
+ token_list_t *list)
+{
+ if (list == NULL)
+ return;
+
+ _glcpp_parser_expand_token_list (parser, list);
+
+ _token_list_trim_trailing_space (list);
+
+ _token_list_print (list);
+}
+
+void
+_check_for_reserved_macro_name (const char *identifier)
+{
+ /* According to the GLSL specification, macro names starting with "__"
+ * or "GL_" are reserved for future use. So, don't allow them.
+ */
+ if (strncmp(identifier, "__", 2) == 0) {
+ fprintf (stderr, "Error: Macro names starting with \"__\" are reserved.\n");
+ exit(1);
+ }
+ if (strncmp(identifier, "GL_", 3) == 0) {
+ fprintf (stderr, "Error: Macro names starting with \"GL_\" are reserved.\n");
+ exit(1);
+ }
+}
+
+void
+_define_object_macro (glcpp_parser_t *parser,
+ const char *identifier,
+ token_list_t *replacements)
+{
+ macro_t *macro;
+
+ _check_for_reserved_macro_name(identifier);
+
+ macro = xtalloc (parser, macro_t);
+
+ macro->is_function = 0;
+ macro->parameters = NULL;
+ macro->identifier = talloc_strdup (macro, identifier);
+ macro->replacements = talloc_steal (macro, replacements);
+
+ hash_table_insert (parser->defines, macro, identifier);
+}
+
+void
+_define_function_macro (glcpp_parser_t *parser,
+ const char *identifier,
+ string_list_t *parameters,
+ token_list_t *replacements)
+{
+ macro_t *macro;
+
+ _check_for_reserved_macro_name(identifier);
+
+ macro = xtalloc (parser, macro_t);
+
+ macro->is_function = 1;
+ macro->parameters = talloc_steal (macro, parameters);
+ macro->identifier = talloc_strdup (macro, identifier);
+ macro->replacements = talloc_steal (macro, replacements);
+
+ hash_table_insert (parser->defines, macro, identifier);
+}
+
+static int
+glcpp_parser_lex (glcpp_parser_t *parser)
+{
+ token_node_t *node;
+ int ret;
+
+ if (parser->lex_from_list == NULL) {
+ ret = glcpp_lex (parser->scanner);
+
+ /* XXX: This ugly block of code exists for the sole
+ * purpose of converting a NEWLINE token into a SPACE
+ * token, but only in the case where we have seen a
+ * function-like macro name, but have not yet seen its
+ * closing parenthesis.
+ *
+ * There's perhaps a more compact way to do this with
+ * mid-rule actions in the grammar.
+ *
+ * I'm definitely not pleased with the complexity of
+ * this code here.
+ */
+ if (parser->newline_as_space)
+ {
+ if (ret == '(') {
+ parser->paren_count++;
+ } else if (ret == ')') {
+ parser->paren_count--;
+ if (parser->paren_count == 0)
+ parser->newline_as_space = 0;
+ } else if (ret == NEWLINE) {
+ ret = SPACE;
+ } else if (ret != SPACE) {
+ if (parser->paren_count == 0)
+ parser->newline_as_space = 0;
+ }
+ }
+ else if (parser->in_control_line)
+ {
+ if (ret == NEWLINE)
+ parser->in_control_line = 0;
+ }
+ else if (ret == HASH_DEFINE_OBJ || ret == HASH_DEFINE_FUNC ||
+ ret == HASH_UNDEF || ret == HASH_IF ||
+ ret == HASH_IFDEF || ret == HASH_IFNDEF ||
+ ret == HASH_ELIF || ret == HASH_ELSE ||
+ ret == HASH_ENDIF || ret == HASH)
+ {
+ parser->in_control_line = 1;
+ }
+ else if (ret == IDENTIFIER)
+ {
+ macro_t *macro;
+ macro = hash_table_find (parser->defines,
+ yylval.str);
+ if (macro && macro->is_function) {
+ parser->newline_as_space = 1;
+ parser->paren_count = 0;
+ }
+ }
+
+ return ret;
+ }
+
+ node = parser->lex_from_node;
+
+ if (node == NULL) {
+ talloc_free (parser->lex_from_list);
+ parser->lex_from_list = NULL;
+ return NEWLINE;
+ }
+
+ yylval = node->token->value;
+ ret = node->token->type;
+
+ parser->lex_from_node = node->next;
+
+ return ret;
+}
+
+static void
+glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list)
+{
+ token_node_t *node;
+
+ assert (parser->lex_from_list == NULL);
+
+ /* Copy list, eliminating any space tokens. */
+ parser->lex_from_list = _token_list_create (parser);
+
+ for (node = list->head; node; node = node->next) {
+ if (node->token->type == SPACE)
+ continue;
+ _token_list_append (parser->lex_from_list, node->token);
+ }
+
+ talloc_free (list);
+
+ parser->lex_from_node = parser->lex_from_list->head;
+
+ /* It's possible the list consisted of nothing but whitespace. */
+ if (parser->lex_from_node == NULL) {
+ talloc_free (parser->lex_from_list);
+ parser->lex_from_list = NULL;
+ }
+}
+
+static void
+_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, int condition)
+{
+ skip_type_t current = SKIP_NO_SKIP;
+ skip_node_t *node;
+
+ if (parser->skip_stack)
+ current = parser->skip_stack->type;
+
+ node = xtalloc (parser, skip_node_t);
+
+ if (current == SKIP_NO_SKIP) {
+ if (condition)
+ node->type = SKIP_NO_SKIP;
+ else
+ node->type = SKIP_TO_ELSE;
+ } else {
+ node->type = SKIP_TO_ENDIF;
+ }
+
+ node->next = parser->skip_stack;
+ parser->skip_stack = node;
+}
+
+static void
+_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, const char *type,
+ int condition)
+{
+ if (parser->skip_stack == NULL) {
+ fprintf (stderr, "Error: %s without #if\n", type);
+ exit (1);
+ }
+
+ if (parser->skip_stack->type == SKIP_TO_ELSE) {
+ if (condition)
+ parser->skip_stack->type = SKIP_NO_SKIP;
+ } else {
+ parser->skip_stack->type = SKIP_TO_ENDIF;
+ }
+}
+
+static void
+_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser)
+{
+ skip_node_t *node;
+
+ if (parser->skip_stack == NULL) {
+ fprintf (stderr, "Error: #endif without #if\n");
+ exit (1);
+ }
+
+ node = parser->skip_stack;
+ parser->skip_stack = node->next;
+ talloc_free (node);
+}
diff --git a/glcpp/glcpp.c b/glcpp/glcpp.c
new file mode 100644
index 0000000..fcdc4ed
--- /dev/null
+++ b/glcpp/glcpp.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "glcpp.h"
+
+extern int yydebug;
+
+int
+main (void)
+{
+ glcpp_parser_t *parser;
+ int ret;
+
+ parser = glcpp_parser_create ();
+
+ ret = glcpp_parser_parse (parser);
+
+ glcpp_parser_destroy (parser);
+
+ return ret;
+}
diff --git a/glcpp/glcpp.h b/glcpp/glcpp.h
new file mode 100644
index 0000000..4459daa
--- /dev/null
+++ b/glcpp/glcpp.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GLCPP_H
+#define GLCPP_H
+
+#include <stdint.h>
+
+#include <talloc.h>
+
+#include "hash_table.h"
+
+#define yyscan_t void*
+
+/* Some data types used for parser values. */
+
+typedef struct string_node {
+ const char *str;
+ struct string_node *next;
+} string_node_t;
+
+typedef struct string_list {
+ string_node_t *head;
+ string_node_t *tail;
+} string_list_t;
+
+typedef struct token token_t;
+typedef struct token_list token_list_t;
+
+typedef union YYSTYPE
+{
+ intmax_t ival;
+ char *str;
+ string_list_t *string_list;
+ token_t *token;
+ token_list_t *token_list;
+} YYSTYPE;
+
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+
+struct token {
+ int type;
+ YYSTYPE value;
+};
+
+typedef struct token_node {
+ token_t *token;
+ struct token_node *next;
+} token_node_t;
+
+struct token_list {
+ token_node_t *head;
+ token_node_t *tail;
+ token_node_t *non_space_tail;
+};
+
+typedef struct argument_node {
+ token_list_t *argument;
+ struct argument_node *next;
+} argument_node_t;
+
+typedef struct argument_list {
+ argument_node_t *head;
+ argument_node_t *tail;
+} argument_list_t;
+
+typedef struct glcpp_parser glcpp_parser_t;
+
+typedef enum {
+ TOKEN_CLASS_IDENTIFIER,
+ TOKEN_CLASS_IDENTIFIER_FINALIZED,
+ TOKEN_CLASS_FUNC_MACRO,
+ TOKEN_CLASS_OBJ_MACRO
+} token_class_t;
+
+token_class_t
+glcpp_parser_classify_token (glcpp_parser_t *parser,
+ const char *identifier,
+ int *parameter_index);
+
+typedef struct {
+ int is_function;
+ string_list_t *parameters;
+ const char *identifier;
+ token_list_t *replacements;
+} macro_t;
+
+typedef struct expansion_node {
+ macro_t *macro;
+ token_node_t *replacements;
+ struct expansion_node *next;
+} expansion_node_t;
+
+typedef enum skip_type {
+ SKIP_NO_SKIP,
+ SKIP_TO_ELSE,
+ SKIP_TO_ENDIF
+} skip_type_t;
+
+typedef struct skip_node {
+ skip_type_t type;
+ struct skip_node *next;
+} skip_node_t;
+
+typedef struct active_list {
+ const char *identifier;
+ token_node_t *marker;
+ struct active_list *next;
+} active_list_t;
+
+struct glcpp_parser {
+ yyscan_t scanner;
+ struct hash_table *defines;
+ active_list_t *active;
+ int lexing_if;
+ int space_tokens;
+ int newline_as_space;
+ int in_control_line;
+ int paren_count;
+ skip_node_t *skip_stack;
+ token_list_t *lex_from_list;
+ token_node_t *lex_from_node;
+};
+
+glcpp_parser_t *
+glcpp_parser_create (void);
+
+int
+glcpp_parser_parse (glcpp_parser_t *parser);
+
+void
+glcpp_parser_destroy (glcpp_parser_t *parser);
+
+/* Generated by glcpp-lex.l to glcpp-lex.c */
+
+int
+glcpp_lex_init_extra (glcpp_parser_t *parser, yyscan_t* scanner);
+
+int
+glcpp_lex (yyscan_t scanner);
+
+int
+glcpp_lex_destroy (yyscan_t scanner);
+
+/* Generated by glcpp-parse.y to glcpp-parse.c */
+
+int
+yyparse (glcpp_parser_t *parser);
+
+/* xtalloc - wrappers around talloc to check for out-of-memory */
+
+#define xtalloc(ctx, type) (type *)xtalloc_named_const(ctx, sizeof(type), #type)
+
+#define xtalloc_size(ctx, size) xtalloc_named_const(ctx, size, __location__)
+
+void *
+xtalloc_named_const (const void *context, size_t size, const char *name);
+
+char *
+xtalloc_strdup (const void *t, const char *p);
+
+char *
+xtalloc_strndup (const void *t, const char *p, size_t n);
+
+char *
+xtalloc_asprintf (const void *t, const char *fmt, ...);
+
+void *
+_xtalloc_reference_loc (const void *context,
+ const void *ptr, const char *location);
+
+#define xtalloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_xtalloc_reference_loc((ctx),(ptr), __location__)
+
+#endif
diff --git a/glcpp/hash_table.c b/glcpp/hash_table.c
new file mode 100644
index 0000000..e89a256
--- /dev/null
+++ b/glcpp/hash_table.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file hash_table.c
+ * \brief Implementation of a generic, opaque hash table data type.
+ *
+ * \author Ian Romanick <ian.d.romanick@intel.com>
+ */
+
+#include "main/imports.h"
+#include "main/simple_list.h"
+#include "hash_table.h"
+
+struct node {
+ struct node *next;
+ struct node *prev;
+};
+
+struct hash_table {
+ hash_func_t hash;
+ hash_compare_func_t compare;
+
+ unsigned num_buckets;
+ struct node buckets[1];
+};
+
+
+struct hash_node {
+ struct node link;
+ const void *key;
+ void *data;
+};
+
+
+struct hash_table *
+hash_table_ctor(unsigned num_buckets, hash_func_t hash,
+ hash_compare_func_t compare)
+{
+ struct hash_table *ht;
+ unsigned i;
+
+
+ if (num_buckets < 16) {
+ num_buckets = 16;
+ }
+
+ ht = _mesa_malloc(sizeof(*ht) + ((num_buckets - 1)
+ * sizeof(ht->buckets[0])));
+ if (ht != NULL) {
+ ht->hash = hash;
+ ht->compare = compare;
+ ht->num_buckets = num_buckets;
+
+ for (i = 0; i < num_buckets; i++) {
+ make_empty_list(& ht->buckets[i]);
+ }
+ }
+
+ return ht;
+}
+
+
+void
+hash_table_dtor(struct hash_table *ht)
+{
+ hash_table_clear(ht);
+ _mesa_free(ht);
+}
+
+
+void
+hash_table_clear(struct hash_table *ht)
+{
+ struct node *node;
+ struct node *temp;
+ unsigned i;
+
+
+ for (i = 0; i < ht->num_buckets; i++) {
+ foreach_s(node, temp, & ht->buckets[i]) {
+ remove_from_list(node);
+ _mesa_free(node);
+ }
+
+ assert(is_empty_list(& ht->buckets[i]));
+ }
+}
+
+
+void *
+hash_table_find(struct hash_table *ht, const void *key)
+{
+ const unsigned hash_value = (*ht->hash)(key);
+ const unsigned bucket = hash_value % ht->num_buckets;
+ struct node *node;
+
+ foreach(node, & ht->buckets[bucket]) {
+ struct hash_node *hn = (struct hash_node *) node;
+
+ if ((*ht->compare)(hn->key, key) == 0) {
+ return hn->data;
+ }
+ }
+
+ return NULL;
+}
+
+
+void
+hash_table_insert(struct hash_table *ht, void *data, const void *key)
+{
+ const unsigned hash_value = (*ht->hash)(key);
+ const unsigned bucket = hash_value % ht->num_buckets;
+ struct hash_node *node;
+
+ node = _mesa_calloc(sizeof(*node));
+
+ node->data = data;
+ node->key = key;
+
+ insert_at_head(& ht->buckets[bucket], & node->link);
+}
+
+
+unsigned
+hash_table_string_hash(const void *key)
+{
+ const char *str = (const char *) key;
+ unsigned hash = 5381;
+
+
+ while (*str != '\0') {
+ hash = (hash * 33) + *str;
+ str++;
+ }
+
+ return hash;
+}
diff --git a/glcpp/hash_table.h b/glcpp/hash_table.h
new file mode 100644
index 0000000..b9dd343
--- /dev/null
+++ b/glcpp/hash_table.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file hash_table.h
+ * \brief Implementation of a generic, opaque hash table data type.
+ *
+ * \author Ian Romanick <ian.d.romanick@intel.com>
+ */
+
+#ifndef HASH_TABLE_H
+#define HASH_TABLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <string.h>
+
+struct hash_table;
+
+typedef unsigned (*hash_func_t)(const void *key);
+typedef int (*hash_compare_func_t)(const void *key1, const void *key2);
+
+/**
+ * Hash table constructor
+ *
+ * Creates a hash table with the specified number of buckets. The supplied
+ * \c hash and \c compare routines are used when adding elements to the table
+ * and when searching for elements in the table.
+ *
+ * \param num_buckets Number of buckets (bins) in the hash table.
+ * \param hash Function used to compute hash value of input keys.
+ * \param compare Function used to compare keys.
+ */
+extern struct hash_table *hash_table_ctor(unsigned num_buckets,
+ hash_func_t hash, hash_compare_func_t compare);
+
+
+/**
+ * Release all memory associated with a hash table
+ *
+ * \warning
+ * This function cannot release memory occupied either by keys or data.
+ */
+extern void hash_table_dtor(struct hash_table *ht);
+
+
+/**
+ * Flush all entries from a hash table
+ *
+ * \param ht Table to be cleared of its entries.
+ */
+extern void hash_table_clear(struct hash_table *ht);
+
+
+/**
+ * Search a hash table for a specific element
+ *
+ * \param ht Table to be searched
+ * \param key Key of the desired element
+ *
+ * \return
+ * The \c data value supplied to \c hash_table_insert when the element with
+ * the matching key was added. If no matching key exists in the table,
+ * \c NULL is returned.
+ */
+extern void *hash_table_find(struct hash_table *ht, const void *key);
+
+
+/**
+ * Add an element to a hash table
+ */
+extern void hash_table_insert(struct hash_table *ht, void *data,
+ const void *key);
+
+
+/**
+ * Compute hash value of a string
+ *
+ * Computes the hash value of a string using the DJB2 algorithm developed by
+ * Professor Daniel J. Bernstein. It was published on comp.lang.c once upon
+ * a time. I was unable to find the original posting in the archives.
+ *
+ * \param key Pointer to a NUL terminated string to be hashed.
+ *
+ * \sa hash_table_string_compare
+ */
+extern unsigned hash_table_string_hash(const void *key);
+
+
+/**
+ * Compare two strings used as keys
+ *
+ * This is just a macro wrapper around \c strcmp.
+ *
+ * \sa hash_table_string_hash
+ */
+#define hash_table_string_compare ((hash_compare_func_t) strcmp)
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* HASH_TABLE_H */
diff --git a/glcpp/main/imports.h b/glcpp/main/imports.h
new file mode 100644
index 0000000..d219734
--- /dev/null
+++ b/glcpp/main/imports.h
@@ -0,0 +1,6 @@
+#include <assert.h>
+#include <stdlib.h>
+
+#define _mesa_malloc(x) malloc(x)
+#define _mesa_free(x) free(x)
+#define _mesa_calloc(x) calloc(1,x)
diff --git a/glcpp/main/simple_list.h b/glcpp/main/simple_list.h
new file mode 100644
index 0000000..5ef39e1
--- /dev/null
+++ b/glcpp/main/simple_list.h
@@ -0,0 +1,235 @@
+/**
+ * \file simple_list.h
+ * Simple macros for type-safe, intrusive lists.
+ *
+ * Intended to work with a list sentinal which is created as an empty
+ * list. Insert & delete are O(1).
+ *
+ * \author
+ * (C) 1997, Keith Whitwell
+ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _SIMPLE_LIST_H
+#define _SIMPLE_LIST_H
+
+struct simple_node {
+ struct simple_node *next;
+ struct simple_node *prev;
+};
+
+/**
+ * Remove an element from list.
+ *
+ * \param elem element to remove.
+ */
+#define remove_from_list(elem) \
+do { \
+ (elem)->next->prev = (elem)->prev; \
+ (elem)->prev->next = (elem)->next; \
+} while (0)
+
+/**
+ * Insert an element to the list head.
+ *
+ * \param list list.
+ * \param elem element to insert.
+ */
+#define insert_at_head(list, elem) \
+do { \
+ (elem)->prev = list; \
+ (elem)->next = (list)->next; \
+ (list)->next->prev = elem; \
+ (list)->next = elem; \
+} while(0)
+
+/**
+ * Insert an element to the list tail.
+ *
+ * \param list list.
+ * \param elem element to insert.
+ */
+#define insert_at_tail(list, elem) \
+do { \
+ (elem)->next = list; \
+ (elem)->prev = (list)->prev; \
+ (list)->prev->next = elem; \
+ (list)->prev = elem; \
+} while(0)
+
+/**
+ * Move an element to the list head.
+ *
+ * \param list list.
+ * \param elem element to move.
+ */
+#define move_to_head(list, elem) \
+do { \
+ remove_from_list(elem); \
+ insert_at_head(list, elem); \
+} while (0)
+
+/**
+ * Move an element to the list tail.
+ *
+ * \param list list.
+ * \param elem element to move.
+ */
+#define move_to_tail(list, elem) \
+do { \
+ remove_from_list(elem); \
+ insert_at_tail(list, elem); \
+} while (0)
+
+/**
+ * Consatinate a cyclic list to a list
+ *
+ * Appends the sequence of nodes starting with \c tail to the list \c head.
+ * A "cyclic list" is a list that does not have a sentinal node. This means
+ * that the data pointed to by \c tail is an actual node, not a dataless
+ * sentinal. Note that if \c tail constist of a single node, this macro
+ * behaves identically to \c insert_at_tail
+ *
+ * \param head Head of the list to be appended to. This may or may not
+ * be a cyclic list.
+ * \param tail Head of the cyclic list to be appended to \c head.
+ * \param temp Temporary \c simple_list used by the macro
+ *
+ * \sa insert_at_tail
+ */
+#define concat_list_and_cycle(head, tail, temp) \
+do { \
+ (head)->prev->next = (tail); \
+ (tail)->prev->next = (head); \
+ (temp) = (head)->prev; \
+ (head)->prev = (tail)->prev; \
+ (tail)->prev = (temp); \
+} while (0)
+
+#define concat_list(head, next_list) \
+do { \
+ (next_list)->next->prev = (head)->prev; \
+ (next_list)->prev->next = (head); \
+ (head)->prev->next = (next_list)->next; \
+ (head)->prev = (next_list)->prev; \
+} while (0)
+
+/**
+ * Make a empty list empty.
+ *
+ * \param sentinal list (sentinal element).
+ */
+#define make_empty_list(sentinal) \
+do { \
+ (sentinal)->next = sentinal; \
+ (sentinal)->prev = sentinal; \
+} while (0)
+
+/**
+ * Get list first element.
+ *
+ * \param list list.
+ *
+ * \return pointer to first element.
+ */
+#define first_elem(list) ((list)->next)
+
+/**
+ * Get list last element.
+ *
+ * \param list list.
+ *
+ * \return pointer to last element.
+ */
+#define last_elem(list) ((list)->prev)
+
+/**
+ * Get next element.
+ *
+ * \param elem element.
+ *
+ * \return pointer to next element.
+ */
+#define next_elem(elem) ((elem)->next)
+
+/**
+ * Get previous element.
+ *
+ * \param elem element.
+ *
+ * \return pointer to previous element.
+ */
+#define prev_elem(elem) ((elem)->prev)
+
+/**
+ * Test whether element is at end of the list.
+ *
+ * \param list list.
+ * \param elem element.
+ *
+ * \return non-zero if element is at end of list, or zero otherwise.
+ */
+#define at_end(list, elem) ((elem) == (list))
+
+/**
+ * Test if a list is empty.
+ *
+ * \param list list.
+ *
+ * \return non-zero if list empty, or zero otherwise.
+ */
+#define is_empty_list(list) ((list)->next == (list))
+
+/**
+ * Walk through the elements of a list.
+ *
+ * \param ptr pointer to the current element.
+ * \param list list.
+ *
+ * \note It should be followed by a { } block or a single statement, as in a \c
+ * for loop.
+ */
+#define foreach(ptr, list) \
+ for( ptr=(list)->next ; ptr!=list ; ptr=(ptr)->next )
+
+/**
+ * Walk through the elements of a list.
+ *
+ * Same as #foreach but lets you unlink the current value during a list
+ * traversal. Useful for freeing a list, element by element.
+ *
+ * \param ptr pointer to the current element.
+ * \param t temporary pointer.
+ * \param list list.
+ *
+ * \note It should be followed by a { } block or a single statement, as in a \c
+ * for loop.
+ */
+#define foreach_s(ptr, t, list) \
+ for(ptr=(list)->next,t=(ptr)->next; list != ptr; ptr=t, t=(t)->next)
+
+#endif
diff --git a/glcpp/tests/000-content-with-spaces.c b/glcpp/tests/000-content-with-spaces.c
new file mode 100644
index 0000000..696cb3a
--- /dev/null
+++ b/glcpp/tests/000-content-with-spaces.c
@@ -0,0 +1 @@
+this is four tokens
diff --git a/glcpp/tests/000-content-with-spaces.c.expected b/glcpp/tests/000-content-with-spaces.c.expected
new file mode 100644
index 0000000..a7fc918
--- /dev/null
+++ b/glcpp/tests/000-content-with-spaces.c.expected
@@ -0,0 +1 @@
+this is four tokens
diff --git a/glcpp/tests/001-define.c b/glcpp/tests/001-define.c
new file mode 100644
index 0000000..cbf2fee
--- /dev/null
+++ b/glcpp/tests/001-define.c
@@ -0,0 +1,2 @@
+#define foo 1
+foo
diff --git a/glcpp/tests/001-define.c.expected b/glcpp/tests/001-define.c.expected
new file mode 100644
index 0000000..a464d9d
--- /dev/null
+++ b/glcpp/tests/001-define.c.expected
@@ -0,0 +1,2 @@
+
+1
diff --git a/glcpp/tests/002-define-chain.c b/glcpp/tests/002-define-chain.c
new file mode 100644
index 0000000..87d75c6
--- /dev/null
+++ b/glcpp/tests/002-define-chain.c
@@ -0,0 +1,3 @@
+#define foo 1
+#define bar foo
+bar
diff --git a/glcpp/tests/002-define-chain.c.expected b/glcpp/tests/002-define-chain.c.expected
new file mode 100644
index 0000000..c6c9ee3
--- /dev/null
+++ b/glcpp/tests/002-define-chain.c.expected
@@ -0,0 +1,3 @@
+
+
+1
diff --git a/glcpp/tests/003-define-chain-reverse.c b/glcpp/tests/003-define-chain-reverse.c
new file mode 100644
index 0000000..a18b724
--- /dev/null
+++ b/glcpp/tests/003-define-chain-reverse.c
@@ -0,0 +1,3 @@
+#define bar foo
+#define foo 1
+bar
diff --git a/glcpp/tests/003-define-chain-reverse.c.expected b/glcpp/tests/003-define-chain-reverse.c.expected
new file mode 100644
index 0000000..c6c9ee3
--- /dev/null
+++ b/glcpp/tests/003-define-chain-reverse.c.expected
@@ -0,0 +1,3 @@
+
+
+1
diff --git a/glcpp/tests/004-define-recursive.c b/glcpp/tests/004-define-recursive.c
new file mode 100644
index 0000000..2ac56ea
--- /dev/null
+++ b/glcpp/tests/004-define-recursive.c
@@ -0,0 +1,6 @@
+#define foo bar
+#define bar baz
+#define baz foo
+foo
+bar
+baz
diff --git a/glcpp/tests/004-define-recursive.c.expected b/glcpp/tests/004-define-recursive.c.expected
new file mode 100644
index 0000000..2d07687
--- /dev/null
+++ b/glcpp/tests/004-define-recursive.c.expected
@@ -0,0 +1,6 @@
+
+
+
+foo
+bar
+baz
diff --git a/glcpp/tests/005-define-composite-chain.c b/glcpp/tests/005-define-composite-chain.c
new file mode 100644
index 0000000..f5521df
--- /dev/null
+++ b/glcpp/tests/005-define-composite-chain.c
@@ -0,0 +1,3 @@
+#define foo 1
+#define bar a foo
+bar
diff --git a/glcpp/tests/005-define-composite-chain.c.expected b/glcpp/tests/005-define-composite-chain.c.expected
new file mode 100644
index 0000000..892975c
--- /dev/null
+++ b/glcpp/tests/005-define-composite-chain.c.expected
@@ -0,0 +1,3 @@
+
+
+a 1
diff --git a/glcpp/tests/006-define-composite-chain-reverse.c b/glcpp/tests/006-define-composite-chain-reverse.c
new file mode 100644
index 0000000..4bb91a1
--- /dev/null
+++ b/glcpp/tests/006-define-composite-chain-reverse.c
@@ -0,0 +1,3 @@
+#define bar a foo
+#define foo 1
+bar
diff --git a/glcpp/tests/006-define-composite-chain-reverse.c.expected b/glcpp/tests/006-define-composite-chain-reverse.c.expected
new file mode 100644
index 0000000..892975c
--- /dev/null
+++ b/glcpp/tests/006-define-composite-chain-reverse.c.expected
@@ -0,0 +1,3 @@
+
+
+a 1
diff --git a/glcpp/tests/007-define-composite-recursive.c b/glcpp/tests/007-define-composite-recursive.c
new file mode 100644
index 0000000..5784565
--- /dev/null
+++ b/glcpp/tests/007-define-composite-recursive.c
@@ -0,0 +1,6 @@
+#define foo a bar
+#define bar b baz
+#define baz c foo
+foo
+bar
+baz
diff --git a/glcpp/tests/007-define-composite-recursive.c.expected b/glcpp/tests/007-define-composite-recursive.c.expected
new file mode 100644
index 0000000..0b0b477
--- /dev/null
+++ b/glcpp/tests/007-define-composite-recursive.c.expected
@@ -0,0 +1,6 @@
+
+
+
+a b c foo
+b c a bar
+c a b baz
diff --git a/glcpp/tests/008-define-empty.c b/glcpp/tests/008-define-empty.c
new file mode 100644
index 0000000..b1bd17e
--- /dev/null
+++ b/glcpp/tests/008-define-empty.c
@@ -0,0 +1,2 @@
+#define foo
+foo
diff --git a/glcpp/tests/008-define-empty.c.expected b/glcpp/tests/008-define-empty.c.expected
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/glcpp/tests/008-define-empty.c.expected
@@ -0,0 +1,2 @@
+
+
diff --git a/glcpp/tests/009-undef.c b/glcpp/tests/009-undef.c
new file mode 100644
index 0000000..3fc1fb4
--- /dev/null
+++ b/glcpp/tests/009-undef.c
@@ -0,0 +1,4 @@
+#define foo 1
+foo
+#undef foo
+foo
diff --git a/glcpp/tests/009-undef.c.expected b/glcpp/tests/009-undef.c.expected
new file mode 100644
index 0000000..9c0b35a
--- /dev/null
+++ b/glcpp/tests/009-undef.c.expected
@@ -0,0 +1,4 @@
+
+1
+
+foo
diff --git a/glcpp/tests/010-undef-re-define.c b/glcpp/tests/010-undef-re-define.c
new file mode 100644
index 0000000..32ff737
--- /dev/null
+++ b/glcpp/tests/010-undef-re-define.c
@@ -0,0 +1,6 @@
+#define foo 1
+foo
+#undef foo
+foo
+#define foo 2
+foo
diff --git a/glcpp/tests/010-undef-re-define.c.expected b/glcpp/tests/010-undef-re-define.c.expected
new file mode 100644
index 0000000..5970f49
--- /dev/null
+++ b/glcpp/tests/010-undef-re-define.c.expected
@@ -0,0 +1,6 @@
+
+1
+
+foo
+
+2
diff --git a/glcpp/tests/011-define-func-empty.c b/glcpp/tests/011-define-func-empty.c
new file mode 100644
index 0000000..d9ce13c
--- /dev/null
+++ b/glcpp/tests/011-define-func-empty.c
@@ -0,0 +1,2 @@
+#define foo()
+foo()
diff --git a/glcpp/tests/011-define-func-empty.c.expected b/glcpp/tests/011-define-func-empty.c.expected
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/glcpp/tests/011-define-func-empty.c.expected
@@ -0,0 +1,2 @@
+
+
diff --git a/glcpp/tests/012-define-func-no-args.c b/glcpp/tests/012-define-func-no-args.c
new file mode 100644
index 0000000..c2bb730
--- /dev/null
+++ b/glcpp/tests/012-define-func-no-args.c
@@ -0,0 +1,2 @@
+#define foo() bar
+foo()
diff --git a/glcpp/tests/012-define-func-no-args.c.expected b/glcpp/tests/012-define-func-no-args.c.expected
new file mode 100644
index 0000000..9f075f2
--- /dev/null
+++ b/glcpp/tests/012-define-func-no-args.c.expected
@@ -0,0 +1,2 @@
+
+bar
diff --git a/glcpp/tests/013-define-func-1-arg-unused.c b/glcpp/tests/013-define-func-1-arg-unused.c
new file mode 100644
index 0000000..f78fb8b
--- /dev/null
+++ b/glcpp/tests/013-define-func-1-arg-unused.c
@@ -0,0 +1,2 @@
+#define foo(x) 1
+foo(bar)
diff --git a/glcpp/tests/013-define-func-1-arg-unused.c.expected b/glcpp/tests/013-define-func-1-arg-unused.c.expected
new file mode 100644
index 0000000..a464d9d
--- /dev/null
+++ b/glcpp/tests/013-define-func-1-arg-unused.c.expected
@@ -0,0 +1,2 @@
+
+1
diff --git a/glcpp/tests/014-define-func-2-arg-unused.c b/glcpp/tests/014-define-func-2-arg-unused.c
new file mode 100644
index 0000000..11feb26
--- /dev/null
+++ b/glcpp/tests/014-define-func-2-arg-unused.c
@@ -0,0 +1,2 @@
+#define foo(x,y) 1
+foo(bar,baz)
diff --git a/glcpp/tests/014-define-func-2-arg-unused.c.expected b/glcpp/tests/014-define-func-2-arg-unused.c.expected
new file mode 100644
index 0000000..a464d9d
--- /dev/null
+++ b/glcpp/tests/014-define-func-2-arg-unused.c.expected
@@ -0,0 +1,2 @@
+
+1
diff --git a/glcpp/tests/015-define-object-with-parens.c b/glcpp/tests/015-define-object-with-parens.c
new file mode 100644
index 0000000..558da9c
--- /dev/null
+++ b/glcpp/tests/015-define-object-with-parens.c
@@ -0,0 +1,4 @@
+#define foo ()1
+foo()
+#define bar ()2
+bar()
diff --git a/glcpp/tests/015-define-object-with-parens.c.expected b/glcpp/tests/015-define-object-with-parens.c.expected
new file mode 100644
index 0000000..a70321a
--- /dev/null
+++ b/glcpp/tests/015-define-object-with-parens.c.expected
@@ -0,0 +1,4 @@
+
+()1()
+
+()2()
diff --git a/glcpp/tests/016-define-func-1-arg.c b/glcpp/tests/016-define-func-1-arg.c
new file mode 100644
index 0000000..a2e2404
--- /dev/null
+++ b/glcpp/tests/016-define-func-1-arg.c
@@ -0,0 +1,2 @@
+#define foo(x) ((x)+1)
+foo(bar)
diff --git a/glcpp/tests/016-define-func-1-arg.c.expected b/glcpp/tests/016-define-func-1-arg.c.expected
new file mode 100644
index 0000000..6bfe04f
--- /dev/null
+++ b/glcpp/tests/016-define-func-1-arg.c.expected
@@ -0,0 +1,2 @@
+
+((bar)+1)
diff --git a/glcpp/tests/017-define-func-2-args.c b/glcpp/tests/017-define-func-2-args.c
new file mode 100644
index 0000000..c725383
--- /dev/null
+++ b/glcpp/tests/017-define-func-2-args.c
@@ -0,0 +1,2 @@
+#define foo(x,y) ((x)*(y))
+foo(bar,baz)
diff --git a/glcpp/tests/017-define-func-2-args.c.expected b/glcpp/tests/017-define-func-2-args.c.expected
new file mode 100644
index 0000000..f7a2b8c
--- /dev/null
+++ b/glcpp/tests/017-define-func-2-args.c.expected
@@ -0,0 +1,2 @@
+
+((bar)*(baz))
diff --git a/glcpp/tests/018-define-func-macro-as-parameter.c b/glcpp/tests/018-define-func-macro-as-parameter.c
new file mode 100644
index 0000000..668130b
--- /dev/null
+++ b/glcpp/tests/018-define-func-macro-as-parameter.c
@@ -0,0 +1,3 @@
+#define x 0
+#define foo(x) x
+foo(1)
diff --git a/glcpp/tests/018-define-func-macro-as-parameter.c.expected b/glcpp/tests/018-define-func-macro-as-parameter.c.expected
new file mode 100644
index 0000000..c6c9ee3
--- /dev/null
+++ b/glcpp/tests/018-define-func-macro-as-parameter.c.expected
@@ -0,0 +1,3 @@
+
+
+1
diff --git a/glcpp/tests/019-define-func-1-arg-multi.c b/glcpp/tests/019-define-func-1-arg-multi.c
new file mode 100644
index 0000000..c4e62b2
--- /dev/null
+++ b/glcpp/tests/019-define-func-1-arg-multi.c
@@ -0,0 +1,2 @@
+#define foo(x) (x)
+foo(this is more than one word)
diff --git a/glcpp/tests/019-define-func-1-arg-multi.c.expected b/glcpp/tests/019-define-func-1-arg-multi.c.expected
new file mode 100644
index 0000000..1e89b8c
--- /dev/null
+++ b/glcpp/tests/019-define-func-1-arg-multi.c.expected
@@ -0,0 +1,2 @@
+
+(this is more than one word)
diff --git a/glcpp/tests/020-define-func-2-arg-multi.c b/glcpp/tests/020-define-func-2-arg-multi.c
new file mode 100644
index 0000000..3049ad1
--- /dev/null
+++ b/glcpp/tests/020-define-func-2-arg-multi.c
@@ -0,0 +1,2 @@
+#define foo(x,y) x,two fish,red fish,y
+foo(one fish, blue fish)
diff --git a/glcpp/tests/020-define-func-2-arg-multi.c.expected b/glcpp/tests/020-define-func-2-arg-multi.c.expected
new file mode 100644
index 0000000..19f59f5
--- /dev/null
+++ b/glcpp/tests/020-define-func-2-arg-multi.c.expected
@@ -0,0 +1,2 @@
+
+one fish,two fish,red fish,blue fish
diff --git a/glcpp/tests/021-define-func-compose.c b/glcpp/tests/021-define-func-compose.c
new file mode 100644
index 0000000..21ddd0e
--- /dev/null
+++ b/glcpp/tests/021-define-func-compose.c
@@ -0,0 +1,3 @@
+#define bar(x) (1+(x))
+#define foo(y) (2*(y))
+foo(bar(3))
diff --git a/glcpp/tests/021-define-func-compose.c.expected b/glcpp/tests/021-define-func-compose.c.expected
new file mode 100644
index 0000000..87f51f0
--- /dev/null
+++ b/glcpp/tests/021-define-func-compose.c.expected
@@ -0,0 +1,3 @@
+
+
+(2*((1+(3))))
diff --git a/glcpp/tests/022-define-func-arg-with-parens.c b/glcpp/tests/022-define-func-arg-with-parens.c
new file mode 100644
index 0000000..c20d73a
--- /dev/null
+++ b/glcpp/tests/022-define-func-arg-with-parens.c
@@ -0,0 +1,2 @@
+#define foo(x) (x)
+foo(argument(including parens)for the win)
diff --git a/glcpp/tests/022-define-func-arg-with-parens.c.expected b/glcpp/tests/022-define-func-arg-with-parens.c.expected
new file mode 100644
index 0000000..1dfc669
--- /dev/null
+++ b/glcpp/tests/022-define-func-arg-with-parens.c.expected
@@ -0,0 +1,2 @@
+
+(argument(including parens)for the win)
diff --git a/glcpp/tests/023-define-extra-whitespace.c b/glcpp/tests/023-define-extra-whitespace.c
new file mode 100644
index 0000000..7ebfed6
--- /dev/null
+++ b/glcpp/tests/023-define-extra-whitespace.c
@@ -0,0 +1,8 @@
+#define noargs() 1
+# define onearg(foo) foo
+ # define twoargs( x , y ) x y
+ # define threeargs( a , b , c ) a b c
+noargs ( )
+onearg ( 2 )
+twoargs ( 3 , 4 )
+threeargs ( 5 , 6 , 7 )
diff --git a/glcpp/tests/023-define-extra-whitespace.c.expected b/glcpp/tests/023-define-extra-whitespace.c.expected
new file mode 100644
index 0000000..9c58275
--- /dev/null
+++ b/glcpp/tests/023-define-extra-whitespace.c.expected
@@ -0,0 +1,8 @@
+
+
+
+
+1
+2
+3 4
+5 6 7
diff --git a/glcpp/tests/024-define-chain-to-self-recursion.c b/glcpp/tests/024-define-chain-to-self-recursion.c
new file mode 100644
index 0000000..e788adc
--- /dev/null
+++ b/glcpp/tests/024-define-chain-to-self-recursion.c
@@ -0,0 +1,3 @@
+#define foo foo
+#define bar foo
+bar
diff --git a/glcpp/tests/024-define-chain-to-self-recursion.c.expected b/glcpp/tests/024-define-chain-to-self-recursion.c.expected
new file mode 100644
index 0000000..15600af
--- /dev/null
+++ b/glcpp/tests/024-define-chain-to-self-recursion.c.expected
@@ -0,0 +1,3 @@
+
+
+foo
diff --git a/glcpp/tests/025-func-macro-as-non-macro.c b/glcpp/tests/025-func-macro-as-non-macro.c
new file mode 100644
index 0000000..b433671
--- /dev/null
+++ b/glcpp/tests/025-func-macro-as-non-macro.c
@@ -0,0 +1,2 @@
+#define foo(bar) bar
+foo bar
diff --git a/glcpp/tests/025-func-macro-as-non-macro.c.expected b/glcpp/tests/025-func-macro-as-non-macro.c.expected
new file mode 100644
index 0000000..4a59f05
--- /dev/null
+++ b/glcpp/tests/025-func-macro-as-non-macro.c.expected
@@ -0,0 +1,2 @@
+
+foo bar
diff --git a/glcpp/tests/026-define-func-extra-newlines.c b/glcpp/tests/026-define-func-extra-newlines.c
new file mode 100644
index 0000000..0d83740
--- /dev/null
+++ b/glcpp/tests/026-define-func-extra-newlines.c
@@ -0,0 +1,6 @@
+#define foo(a) bar
+
+foo
+(
+1
+)
diff --git a/glcpp/tests/026-define-func-extra-newlines.c.expected b/glcpp/tests/026-define-func-extra-newlines.c.expected
new file mode 100644
index 0000000..5e3c70f
--- /dev/null
+++ b/glcpp/tests/026-define-func-extra-newlines.c.expected
@@ -0,0 +1,3 @@
+
+
+bar
diff --git a/glcpp/tests/027-define-chain-obj-to-func.c b/glcpp/tests/027-define-chain-obj-to-func.c
new file mode 100644
index 0000000..5ccb52c
--- /dev/null
+++ b/glcpp/tests/027-define-chain-obj-to-func.c
@@ -0,0 +1,3 @@
+#define failure() success
+#define foo failure()
+foo
diff --git a/glcpp/tests/027-define-chain-obj-to-func.c.expected b/glcpp/tests/027-define-chain-obj-to-func.c.expected
new file mode 100644
index 0000000..94c15f9
--- /dev/null
+++ b/glcpp/tests/027-define-chain-obj-to-func.c.expected
@@ -0,0 +1,3 @@
+
+
+success
diff --git a/glcpp/tests/028-define-chain-obj-to-non-func.c b/glcpp/tests/028-define-chain-obj-to-non-func.c
new file mode 100644
index 0000000..44962a7
--- /dev/null
+++ b/glcpp/tests/028-define-chain-obj-to-non-func.c
@@ -0,0 +1,3 @@
+#define success() failure
+#define foo success
+foo
diff --git a/glcpp/tests/028-define-chain-obj-to-non-func.c.expected b/glcpp/tests/028-define-chain-obj-to-non-func.c.expected
new file mode 100644
index 0000000..94c15f9
--- /dev/null
+++ b/glcpp/tests/028-define-chain-obj-to-non-func.c.expected
@@ -0,0 +1,3 @@
+
+
+success
diff --git a/glcpp/tests/029-define-chain-obj-to-func-with-args.c b/glcpp/tests/029-define-chain-obj-to-func-with-args.c
new file mode 100644
index 0000000..261f7d2
--- /dev/null
+++ b/glcpp/tests/029-define-chain-obj-to-func-with-args.c
@@ -0,0 +1,3 @@
+#define bar(failure) failure
+#define foo bar(success)
+foo
diff --git a/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected b/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected
new file mode 100644
index 0000000..94c15f9
--- /dev/null
+++ b/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected
@@ -0,0 +1,3 @@
+
+
+success
diff --git a/glcpp/tests/030-define-chain-obj-to-func-compose.c b/glcpp/tests/030-define-chain-obj-to-func-compose.c
new file mode 100644
index 0000000..e56fbef
--- /dev/null
+++ b/glcpp/tests/030-define-chain-obj-to-func-compose.c
@@ -0,0 +1,4 @@
+#define baz(failure) failure
+#define bar(failure) failure
+#define foo bar(baz(success))
+foo
diff --git a/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected b/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected
new file mode 100644
index 0000000..bed826e
--- /dev/null
+++ b/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected
@@ -0,0 +1,4 @@
+
+
+
+success
diff --git a/glcpp/tests/031-define-chain-func-to-func-compose.c b/glcpp/tests/031-define-chain-func-to-func-compose.c
new file mode 100644
index 0000000..3f4c874
--- /dev/null
+++ b/glcpp/tests/031-define-chain-func-to-func-compose.c
@@ -0,0 +1,4 @@
+#define baz(failure) failure
+#define bar(failure) failure
+#define foo() bar(baz(success))
+foo()
diff --git a/glcpp/tests/031-define-chain-func-to-func-compose.c.expected b/glcpp/tests/031-define-chain-func-to-func-compose.c.expected
new file mode 100644
index 0000000..bed826e
--- /dev/null
+++ b/glcpp/tests/031-define-chain-func-to-func-compose.c.expected
@@ -0,0 +1,4 @@
+
+
+
+success
diff --git a/glcpp/tests/032-define-func-self-recurse.c b/glcpp/tests/032-define-func-self-recurse.c
new file mode 100644
index 0000000..b3ac70f
--- /dev/null
+++ b/glcpp/tests/032-define-func-self-recurse.c
@@ -0,0 +1,2 @@
+#define foo(a) foo(2*(a))
+foo(3)
diff --git a/glcpp/tests/032-define-func-self-recurse.c.expected b/glcpp/tests/032-define-func-self-recurse.c.expected
new file mode 100644
index 0000000..983f941
--- /dev/null
+++ b/glcpp/tests/032-define-func-self-recurse.c.expected
@@ -0,0 +1,2 @@
+
+foo(2*(3))
diff --git a/glcpp/tests/033-define-func-self-compose.c b/glcpp/tests/033-define-func-self-compose.c
new file mode 100644
index 0000000..f65e482
--- /dev/null
+++ b/glcpp/tests/033-define-func-self-compose.c
@@ -0,0 +1,2 @@
+#define foo(a) foo(2*(a))
+foo(foo(3))
diff --git a/glcpp/tests/033-define-func-self-compose.c.expected b/glcpp/tests/033-define-func-self-compose.c.expected
new file mode 100644
index 0000000..0818362
--- /dev/null
+++ b/glcpp/tests/033-define-func-self-compose.c.expected
@@ -0,0 +1,2 @@
+
+foo(2*(foo(2*(3))))
diff --git a/glcpp/tests/034-define-func-self-compose-non-func.c b/glcpp/tests/034-define-func-self-compose-non-func.c
new file mode 100644
index 0000000..209a5f7
--- /dev/null
+++ b/glcpp/tests/034-define-func-self-compose-non-func.c
@@ -0,0 +1,2 @@
+#define foo(bar) bar
+foo(foo)
diff --git a/glcpp/tests/034-define-func-self-compose-non-func.c.expected b/glcpp/tests/034-define-func-self-compose-non-func.c.expected
new file mode 100644
index 0000000..3f808fe
--- /dev/null
+++ b/glcpp/tests/034-define-func-self-compose-non-func.c.expected
@@ -0,0 +1,2 @@
+
+foo
diff --git a/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c b/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c
new file mode 100644
index 0000000..c307fbe
--- /dev/null
+++ b/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c
@@ -0,0 +1,2 @@
+#define foo(bar) bar
+foo(1+foo)
diff --git a/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected b/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected
new file mode 100644
index 0000000..09dfdd6
--- /dev/null
+++ b/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected
@@ -0,0 +1,2 @@
+
+1+foo
diff --git a/glcpp/tests/036-define-func-non-macro-multi-token-argument.c b/glcpp/tests/036-define-func-non-macro-multi-token-argument.c
new file mode 100644
index 0000000..b21ff33
--- /dev/null
+++ b/glcpp/tests/036-define-func-non-macro-multi-token-argument.c
@@ -0,0 +1,3 @@
+#define bar success
+#define foo(x) x
+foo(more bar)
diff --git a/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected b/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected
new file mode 100644
index 0000000..580ed95
--- /dev/null
+++ b/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected
@@ -0,0 +1,3 @@
+
+
+more success
diff --git a/glcpp/tests/037-finalize-unexpanded-macro.c b/glcpp/tests/037-finalize-unexpanded-macro.c
new file mode 100644
index 0000000..b3a2f37
--- /dev/null
+++ b/glcpp/tests/037-finalize-unexpanded-macro.c
@@ -0,0 +1,3 @@
+#define expand(x) expand(x once)
+#define foo(x) x
+foo(expand(just))
diff --git a/glcpp/tests/037-finalize-unexpanded-macro.c.expected b/glcpp/tests/037-finalize-unexpanded-macro.c.expected
new file mode 100644
index 0000000..e804d7e
--- /dev/null
+++ b/glcpp/tests/037-finalize-unexpanded-macro.c.expected
@@ -0,0 +1,3 @@
+
+
+expand(just once)
diff --git a/glcpp/tests/038-func-arg-with-commas.c b/glcpp/tests/038-func-arg-with-commas.c
new file mode 100644
index 0000000..1407c7d
--- /dev/null
+++ b/glcpp/tests/038-func-arg-with-commas.c
@@ -0,0 +1,2 @@
+#define foo(x) success
+foo(argument (with,embedded , commas) -- tricky)
diff --git a/glcpp/tests/038-func-arg-with-commas.c.expected b/glcpp/tests/038-func-arg-with-commas.c.expected
new file mode 100644
index 0000000..6544adb
--- /dev/null
+++ b/glcpp/tests/038-func-arg-with-commas.c.expected
@@ -0,0 +1,2 @@
+
+success
diff --git a/glcpp/tests/039-func-arg-obj-macro-with-comma.c b/glcpp/tests/039-func-arg-obj-macro-with-comma.c
new file mode 100644
index 0000000..0f7fe63
--- /dev/null
+++ b/glcpp/tests/039-func-arg-obj-macro-with-comma.c
@@ -0,0 +1,3 @@
+#define foo(a) (a)
+#define bar two,words
+foo(bar)
diff --git a/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected b/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected
new file mode 100644
index 0000000..8a15397
--- /dev/null
+++ b/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected
@@ -0,0 +1,3 @@
+
+
+(two,words)
diff --git a/glcpp/tests/040-token-pasting.c b/glcpp/tests/040-token-pasting.c
new file mode 100644
index 0000000..caab3ba
--- /dev/null
+++ b/glcpp/tests/040-token-pasting.c
@@ -0,0 +1,2 @@
+#define paste(a,b) a ## b
+paste(one , token)
diff --git a/glcpp/tests/040-token-pasting.c.expected b/glcpp/tests/040-token-pasting.c.expected
new file mode 100644
index 0000000..48e836e
--- /dev/null
+++ b/glcpp/tests/040-token-pasting.c.expected
@@ -0,0 +1,2 @@
+
+onetoken
diff --git a/glcpp/tests/041-if-0.c b/glcpp/tests/041-if-0.c
new file mode 100644
index 0000000..2cab677
--- /dev/null
+++ b/glcpp/tests/041-if-0.c
@@ -0,0 +1,5 @@
+success_1
+#if 0
+failure
+#endif
+success_2
diff --git a/glcpp/tests/041-if-0.c.expected b/glcpp/tests/041-if-0.c.expected
new file mode 100644
index 0000000..8b506b3
--- /dev/null
+++ b/glcpp/tests/041-if-0.c.expected
@@ -0,0 +1,5 @@
+success_1
+
+
+
+success_2
diff --git a/glcpp/tests/042-if-1.c b/glcpp/tests/042-if-1.c
new file mode 100644
index 0000000..874a25c
--- /dev/null
+++ b/glcpp/tests/042-if-1.c
@@ -0,0 +1,5 @@
+success_1
+#if 1
+success_2
+#endif
+success_3
diff --git a/glcpp/tests/042-if-1.c.expected b/glcpp/tests/042-if-1.c.expected
new file mode 100644
index 0000000..a6ae946
--- /dev/null
+++ b/glcpp/tests/042-if-1.c.expected
@@ -0,0 +1,5 @@
+success_1
+
+success_2
+
+success_3
diff --git a/glcpp/tests/043-if-0-else.c b/glcpp/tests/043-if-0-else.c
new file mode 100644
index 0000000..323351f
--- /dev/null
+++ b/glcpp/tests/043-if-0-else.c
@@ -0,0 +1,7 @@
+success_1
+#if 0
+failure
+#else
+success_2
+#endif
+success_3
diff --git a/glcpp/tests/043-if-0-else.c.expected b/glcpp/tests/043-if-0-else.c.expected
new file mode 100644
index 0000000..3d7e6be
--- /dev/null
+++ b/glcpp/tests/043-if-0-else.c.expected
@@ -0,0 +1,7 @@
+success_1
+
+
+
+success_2
+
+success_3
diff --git a/glcpp/tests/044-if-1-else.c b/glcpp/tests/044-if-1-else.c
new file mode 100644
index 0000000..28dfc25
--- /dev/null
+++ b/glcpp/tests/044-if-1-else.c
@@ -0,0 +1,7 @@
+success_1
+#if 1
+success_2
+#else
+failure
+#endif
+success_3
diff --git a/glcpp/tests/044-if-1-else.c.expected b/glcpp/tests/044-if-1-else.c.expected
new file mode 100644
index 0000000..4a31e1c
--- /dev/null
+++ b/glcpp/tests/044-if-1-else.c.expected
@@ -0,0 +1,7 @@
+success_1
+
+success_2
+
+
+
+success_3
diff --git a/glcpp/tests/045-if-0-elif.c b/glcpp/tests/045-if-0-elif.c
new file mode 100644
index 0000000..e50f686
--- /dev/null
+++ b/glcpp/tests/045-if-0-elif.c
@@ -0,0 +1,11 @@
+success_1
+#if 0
+failure_1
+#elif 0
+failure_2
+#elif 1
+success_3
+#elif 1
+failure_3
+#endif
+success_4
diff --git a/glcpp/tests/045-if-0-elif.c.expected b/glcpp/tests/045-if-0-elif.c.expected
new file mode 100644
index 0000000..a9bb158
--- /dev/null
+++ b/glcpp/tests/045-if-0-elif.c.expected
@@ -0,0 +1,11 @@
+success_1
+
+
+
+
+
+success_3
+
+
+
+success_4
diff --git a/glcpp/tests/046-if-1-elsif.c b/glcpp/tests/046-if-1-elsif.c
new file mode 100644
index 0000000..130515a
--- /dev/null
+++ b/glcpp/tests/046-if-1-elsif.c
@@ -0,0 +1,11 @@
+success_1
+#if 1
+success_2
+#elif 0
+failure_1
+#elif 1
+failure_2
+#elif 0
+failure_3
+#endif
+success_3
diff --git a/glcpp/tests/046-if-1-elsif.c.expected b/glcpp/tests/046-if-1-elsif.c.expected
new file mode 100644
index 0000000..a499571
--- /dev/null
+++ b/glcpp/tests/046-if-1-elsif.c.expected
@@ -0,0 +1,11 @@
+success_1
+
+success_2
+
+
+
+
+
+
+
+success_3
diff --git a/glcpp/tests/047-if-elif-else.c b/glcpp/tests/047-if-elif-else.c
new file mode 100644
index 0000000..e8f0838
--- /dev/null
+++ b/glcpp/tests/047-if-elif-else.c
@@ -0,0 +1,11 @@
+success_1
+#if 0
+failure_1
+#elif 0
+failure_2
+#elif 0
+failure_3
+#else
+success_2
+#endif
+success_3
diff --git a/glcpp/tests/047-if-elif-else.c.expected b/glcpp/tests/047-if-elif-else.c.expected
new file mode 100644
index 0000000..54d3086
--- /dev/null
+++ b/glcpp/tests/047-if-elif-else.c.expected
@@ -0,0 +1,11 @@
+success_1
+
+
+
+
+
+
+
+success_2
+
+success_3
diff --git a/glcpp/tests/048-if-nested.c b/glcpp/tests/048-if-nested.c
new file mode 100644
index 0000000..fc4679c
--- /dev/null
+++ b/glcpp/tests/048-if-nested.c
@@ -0,0 +1,11 @@
+success_1
+#if 0
+failure_1
+#if 1
+failure_2
+#else
+failure_3
+#endif
+failure_4
+#endif
+success_2
diff --git a/glcpp/tests/048-if-nested.c.expected b/glcpp/tests/048-if-nested.c.expected
new file mode 100644
index 0000000..8beb9c3
--- /dev/null
+++ b/glcpp/tests/048-if-nested.c.expected
@@ -0,0 +1,11 @@
+success_1
+
+
+
+
+
+
+
+
+
+success_2
diff --git a/glcpp/tests/049-if-expression-precedence.c b/glcpp/tests/049-if-expression-precedence.c
new file mode 100644
index 0000000..833ea03
--- /dev/null
+++ b/glcpp/tests/049-if-expression-precedence.c
@@ -0,0 +1,5 @@
+#if 1 + 2 * 3 + - (25 % 17 - + 1)
+failure with operator precedence
+#else
+success
+#endif
diff --git a/glcpp/tests/049-if-expression-precedence.c.expected b/glcpp/tests/049-if-expression-precedence.c.expected
new file mode 100644
index 0000000..729bdd1
--- /dev/null
+++ b/glcpp/tests/049-if-expression-precedence.c.expected
@@ -0,0 +1,5 @@
+
+
+
+success
+
diff --git a/glcpp/tests/050-if-defined.c b/glcpp/tests/050-if-defined.c
new file mode 100644
index 0000000..34f0f95
--- /dev/null
+++ b/glcpp/tests/050-if-defined.c
@@ -0,0 +1,17 @@
+#if defined foo
+failure_1
+#else
+success_1
+#endif
+#define foo
+#if defined foo
+success_2
+#else
+failure_2
+#endif
+#undef foo
+#if defined foo
+failure_3
+#else
+success_3
+#endif
diff --git a/glcpp/tests/050-if-defined.c.expected b/glcpp/tests/050-if-defined.c.expected
new file mode 100644
index 0000000..737eb8d
--- /dev/null
+++ b/glcpp/tests/050-if-defined.c.expected
@@ -0,0 +1,17 @@
+
+
+
+success_1
+
+
+
+success_2
+
+
+
+
+
+
+
+success_3
+
diff --git a/glcpp/tests/051-if-relational.c b/glcpp/tests/051-if-relational.c
new file mode 100644
index 0000000..c3db488
--- /dev/null
+++ b/glcpp/tests/051-if-relational.c
@@ -0,0 +1,35 @@
+#if 3 < 2
+failure_1
+#else
+success_1
+#endif
+
+#if 3 >= 2
+success_2
+#else
+failure_2
+#endif
+
+#if 2 + 3 <= 5
+success_3
+#else
+failure_3
+#endif
+
+#if 3 - 2 == 1
+success_3
+#else
+failure_3
+#endif
+
+#if 1 > 3
+failure_4
+#else
+success_4
+#endif
+
+#if 1 != 5
+success_5
+#else
+failure_5
+#endif
diff --git a/glcpp/tests/051-if-relational.c.expected b/glcpp/tests/051-if-relational.c.expected
new file mode 100644
index 0000000..652fefd
--- /dev/null
+++ b/glcpp/tests/051-if-relational.c.expected
@@ -0,0 +1,35 @@
+
+
+
+success_1
+
+
+
+success_2
+
+
+
+
+
+success_3
+
+
+
+
+
+success_3
+
+
+
+
+
+
+
+success_4
+
+
+
+success_5
+
+
+
diff --git a/glcpp/tests/052-if-bitwise.c b/glcpp/tests/052-if-bitwise.c
new file mode 100644
index 0000000..2d8e45e
--- /dev/null
+++ b/glcpp/tests/052-if-bitwise.c
@@ -0,0 +1,20 @@
+#if (0xaaaaaaaa | 0x55555555) != 4294967295
+failure_1
+#else
+success_1
+#endif
+#if (0x12345678 ^ 0xfdecba98) == 4023971040
+success_2
+#else
+failure_2
+#endif
+#if (~ 0xdeadbeef) != -3735928560
+failure_3
+#else
+success_3
+#endif
+#if (0667 & 0733) == 403
+success_4
+#else
+failure_4
+#endif
diff --git a/glcpp/tests/052-if-bitwise.c.expected b/glcpp/tests/052-if-bitwise.c.expected
new file mode 100644
index 0000000..44e52b2
--- /dev/null
+++ b/glcpp/tests/052-if-bitwise.c.expected
@@ -0,0 +1,20 @@
+
+
+
+success_1
+
+
+success_2
+
+
+
+
+
+
+success_3
+
+
+success_4
+
+
+
diff --git a/glcpp/tests/053-if-divide-and-shift.c b/glcpp/tests/053-if-divide-and-shift.c
new file mode 100644
index 0000000..d24c54a
--- /dev/null
+++ b/glcpp/tests/053-if-divide-and-shift.c
@@ -0,0 +1,15 @@
+#if (15 / 2) != 7
+failure_1
+#else
+success_1
+#endif
+#if (1 << 12) == 4096
+success_2
+#else
+failure_2
+#endif
+#if (31762 >> 8) != 124
+failure_3
+#else
+success_3
+#endif
diff --git a/glcpp/tests/053-if-divide-and-shift.c.expected b/glcpp/tests/053-if-divide-and-shift.c.expected
new file mode 100644
index 0000000..7e78e04
--- /dev/null
+++ b/glcpp/tests/053-if-divide-and-shift.c.expected
@@ -0,0 +1,15 @@
+
+
+
+success_1
+
+
+success_2
+
+
+
+
+
+
+success_3
+
diff --git a/glcpp/tests/054-if-with-macros.c b/glcpp/tests/054-if-with-macros.c
new file mode 100644
index 0000000..3da79a0
--- /dev/null
+++ b/glcpp/tests/054-if-with-macros.c
@@ -0,0 +1,34 @@
+#define one 1
+#define two 2
+#define three 3
+#define five 5
+#if five < two
+failure_1
+#else
+success_1
+#endif
+#if three >= two
+success_2
+#else
+failure_2
+#endif
+#if two + three <= five
+success_3
+#else
+failure_3
+#endif
+#if five - two == three
+success_4
+#else
+failure_4
+#endif
+#if one > three
+failure_5
+#else
+success_5
+#endif
+#if one != five
+success_6
+#else
+failure_6
+#endif
diff --git a/glcpp/tests/054-if-with-macros.c.expected b/glcpp/tests/054-if-with-macros.c.expected
new file mode 100644
index 0000000..70f737c
--- /dev/null
+++ b/glcpp/tests/054-if-with-macros.c.expected
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+success_1
+
+
+success_2
+
+
+
+
+success_3
+
+
+
+
+success_4
+
+
+
+
+
+
+success_5
+
+
+success_6
+
+
+
diff --git a/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c b/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c
new file mode 100644
index 0000000..00f2c23
--- /dev/null
+++ b/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c
@@ -0,0 +1,3 @@
+#define failure() success
+#define foo failure
+foo()
diff --git a/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected b/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected
new file mode 100644
index 0000000..94c15f9
--- /dev/null
+++ b/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected
@@ -0,0 +1,3 @@
+
+
+success
diff --git a/glcpp/tests/056-macro-argument-with-comma.c b/glcpp/tests/056-macro-argument-with-comma.c
new file mode 100644
index 0000000..58701d1
--- /dev/null
+++ b/glcpp/tests/056-macro-argument-with-comma.c
@@ -0,0 +1,4 @@
+#define bar with,embedded,commas
+#define function(x) success
+#define foo function
+foo(bar)
diff --git a/glcpp/tests/056-macro-argument-with-comma.c.expected b/glcpp/tests/056-macro-argument-with-comma.c.expected
new file mode 100644
index 0000000..bed826e
--- /dev/null
+++ b/glcpp/tests/056-macro-argument-with-comma.c.expected
@@ -0,0 +1,4 @@
+
+
+
+success
diff --git a/glcpp/tests/057-empty-arguments.c b/glcpp/tests/057-empty-arguments.c
new file mode 100644
index 0000000..6140232
--- /dev/null
+++ b/glcpp/tests/057-empty-arguments.c
@@ -0,0 +1,6 @@
+#define zero() success
+zero()
+#define one(x) success
+one()
+#define two(x,y) success
+two(,)
diff --git a/glcpp/tests/057-empty-arguments.c.expected b/glcpp/tests/057-empty-arguments.c.expected
new file mode 100644
index 0000000..7d97e15
--- /dev/null
+++ b/glcpp/tests/057-empty-arguments.c.expected
@@ -0,0 +1,6 @@
+
+success
+
+success
+
+success
diff --git a/glcpp/tests/058-token-pasting-empty-arguments.c b/glcpp/tests/058-token-pasting-empty-arguments.c
new file mode 100644
index 0000000..8ac260c
--- /dev/null
+++ b/glcpp/tests/058-token-pasting-empty-arguments.c
@@ -0,0 +1,5 @@
+#define paste(x,y) x ## y
+paste(a,b)
+paste(a,)
+paste(,b)
+paste(,)
diff --git a/glcpp/tests/058-token-pasting-empty-arguments.c.expected b/glcpp/tests/058-token-pasting-empty-arguments.c.expected
new file mode 100644
index 0000000..e0967a1
--- /dev/null
+++ b/glcpp/tests/058-token-pasting-empty-arguments.c.expected
@@ -0,0 +1,5 @@
+
+ab
+a
+b
+
diff --git a/glcpp/tests/059-token-pasting-integer.c b/glcpp/tests/059-token-pasting-integer.c
new file mode 100644
index 0000000..37b895a
--- /dev/null
+++ b/glcpp/tests/059-token-pasting-integer.c
@@ -0,0 +1,4 @@
+#define paste(x,y) x ## y
+paste(1,2)
+paste(1,000)
+paste(identifier,2)
diff --git a/glcpp/tests/059-token-pasting-integer.c.expected b/glcpp/tests/059-token-pasting-integer.c.expected
new file mode 100644
index 0000000..f1288aa
--- /dev/null
+++ b/glcpp/tests/059-token-pasting-integer.c.expected
@@ -0,0 +1,4 @@
+
+12
+1000
+identifier2
diff --git a/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c b/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c
new file mode 100644
index 0000000..ed80ea8
--- /dev/null
+++ b/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c
@@ -0,0 +1,3 @@
+#define double(a) a*2
+#define foo double(
+foo 5)
diff --git a/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected b/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected
new file mode 100644
index 0000000..3e5501a
--- /dev/null
+++ b/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected
@@ -0,0 +1,3 @@
+
+
+5*2
diff --git a/glcpp/tests/061-define-chain-obj-to-func-multi.c b/glcpp/tests/061-define-chain-obj-to-func-multi.c
new file mode 100644
index 0000000..6dbfd1f
--- /dev/null
+++ b/glcpp/tests/061-define-chain-obj-to-func-multi.c
@@ -0,0 +1,5 @@
+#define foo(x) success
+#define bar foo
+#define baz bar
+#define joe baz
+joe (failure)
diff --git a/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected b/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected
new file mode 100644
index 0000000..15eb64b
--- /dev/null
+++ b/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected
@@ -0,0 +1,5 @@
+
+
+
+
+success
diff --git a/glcpp/tests/062-if-0-skips-garbage.c b/glcpp/tests/062-if-0-skips-garbage.c
new file mode 100644
index 0000000..d9e439b
--- /dev/null
+++ b/glcpp/tests/062-if-0-skips-garbage.c
@@ -0,0 +1,5 @@
+#define foo(a,b)
+#if 0
+foo(bar)
+foo(
+#endif
diff --git a/glcpp/tests/062-if-0-skips-garbage.c.expected b/glcpp/tests/062-if-0-skips-garbage.c.expected
new file mode 100644
index 0000000..3f2ff2d
--- /dev/null
+++ b/glcpp/tests/062-if-0-skips-garbage.c.expected
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/glcpp/tests/063-comments.c b/glcpp/tests/063-comments.c
new file mode 100644
index 0000000..e641d2f
--- /dev/null
+++ b/glcpp/tests/063-comments.c
@@ -0,0 +1,20 @@
+/* this is a comment */
+// so is this
+// */
+f = g/**//h;
+/*//*/l();
+m = n//**/o
++ p;
+/* this
+comment spans
+multiple lines and
+contains *** stars
+and slashes / *** /
+and other stuff.
+****/
+more code here
+/* Test that /* nested
+ comments */
+are not treated like comments.
+/*/ this is a comment */
+/*/*/
diff --git a/glcpp/tests/063-comments.c.expected b/glcpp/tests/063-comments.c.expected
new file mode 100644
index 0000000..4998d76
--- /dev/null
+++ b/glcpp/tests/063-comments.c.expected
@@ -0,0 +1,13 @@
+
+
+
+f = g /h;
+ l();
+m = n
++ p;
+
+more code here
+
+are not treated like comments.
+
+
diff --git a/glcpp/tests/071-punctuator.c b/glcpp/tests/071-punctuator.c
new file mode 100644
index 0000000..959d682
--- /dev/null
+++ b/glcpp/tests/071-punctuator.c
@@ -0,0 +1 @@
+a = b
diff --git a/glcpp/tests/071-punctuator.c.expected b/glcpp/tests/071-punctuator.c.expected
new file mode 100644
index 0000000..959d682
--- /dev/null
+++ b/glcpp/tests/071-punctuator.c.expected
@@ -0,0 +1 @@
+a = b
diff --git a/glcpp/tests/072-token-pasting-same-line.c b/glcpp/tests/072-token-pasting-same-line.c
new file mode 100644
index 0000000..e421e9d
--- /dev/null
+++ b/glcpp/tests/072-token-pasting-same-line.c
@@ -0,0 +1,2 @@
+#define paste(x) success_ ## x
+paste(1) paste(2) paste(3)
diff --git a/glcpp/tests/072-token-pasting-same-line.c.expected b/glcpp/tests/072-token-pasting-same-line.c.expected
new file mode 100644
index 0000000..7b80af7
--- /dev/null
+++ b/glcpp/tests/072-token-pasting-same-line.c.expected
@@ -0,0 +1,2 @@
+
+success_1 success_2 success_3
diff --git a/glcpp/tests/099-c99-example.c b/glcpp/tests/099-c99-example.c
new file mode 100644
index 0000000..d1976b1
--- /dev/null
+++ b/glcpp/tests/099-c99-example.c
@@ -0,0 +1,17 @@
+#define x 3
+#define f(a) f(x * (a))
+#undef x
+#define x 2
+#define g f
+#define z z[0]
+#define h g(~
+#define m(a) a(w)
+#define w 0,1
+#define t(a) a
+#define p() int
+#define q(x) x
+#define r(x,y) x ## y
+f(y+1) + f(f(z)) % t(t(g)(0) + t)(1);
+g(x +(3,4)-w) | h 5) & m
+ (f)^m(m);
+p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,)};
diff --git a/glcpp/tests/099-c99-example.c.expected b/glcpp/tests/099-c99-example.c.expected
new file mode 100644
index 0000000..352bbff
--- /dev/null
+++ b/glcpp/tests/099-c99-example.c.expected
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
+f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1);
+int i[] = { 1, 23, 4, 5, };
diff --git a/glcpp/tests/glcpp-test b/glcpp/tests/glcpp-test
new file mode 100755
index 0000000..396f6e1
--- /dev/null
+++ b/glcpp/tests/glcpp-test
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+for test in *.c; do
+ echo "Testing $test"
+ ../glcpp < $test > $test.out
+ diff -u $test.expected $test.out
+done
diff --git a/glcpp/xtalloc.c b/glcpp/xtalloc.c
new file mode 100644
index 0000000..656ac2d
--- /dev/null
+++ b/glcpp/xtalloc.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <talloc.h>
+
+void *
+xtalloc_named_const (const void *context, size_t size, const char *name)
+{
+ void *ret;
+
+ ret = talloc_named_const (context, size, name);
+ if (ret == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ exit (1);
+ }
+
+ return ret;
+}
+
+char *
+xtalloc_strdup (const void *t, const char *p)
+{
+ char *ret;
+
+ ret = talloc_strdup (t, p);
+ if (ret == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ exit (1);
+ }
+
+ return ret;
+}
+
+char *
+xtalloc_strndup (const void *t, const char *p, size_t n)
+{
+ char *ret;
+
+ ret = talloc_strndup (t, p, n);
+ if (ret == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ exit (1);
+ }
+
+ return ret;
+}
+
+char *
+xtalloc_asprintf (const void *t, const char *fmt, ...)
+{
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+
+ ret = talloc_vasprintf(t, fmt, ap);
+ if (ret == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ exit (1);
+ }
+
+ va_end(ap);
+ return ret;
+}
+
+void *
+_xtalloc_reference_loc (const void *context,
+ const void *ptr, const char *location)
+{
+ void *ret;
+
+ ret = _talloc_reference_loc (context, ptr, location);
+ if (ret == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ exit (1);
+ }
+
+ return ret;
+}