Merge Carl's preprocessor into the glcpp subdirectory.
authorKenneth Graunke <kenneth@whitecape.org>
Mon, 21 Jun 2010 18:22:11 +0000 (11:22 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Mon, 21 Jun 2010 18:22:11 +0000 (11:22 -0700)
147 files changed:
1  2 
glcpp/.gitignore
glcpp/Makefile
glcpp/README
glcpp/glcpp-lex.l
glcpp/glcpp-parse.y
glcpp/glcpp.c
glcpp/glcpp.h
glcpp/hash_table.c
glcpp/hash_table.h
glcpp/main/imports.h
glcpp/main/simple_list.h
glcpp/tests/000-content-with-spaces.c
glcpp/tests/000-content-with-spaces.c.expected
glcpp/tests/001-define.c
glcpp/tests/001-define.c.expected
glcpp/tests/002-define-chain.c
glcpp/tests/002-define-chain.c.expected
glcpp/tests/003-define-chain-reverse.c
glcpp/tests/003-define-chain-reverse.c.expected
glcpp/tests/004-define-recursive.c
glcpp/tests/004-define-recursive.c.expected
glcpp/tests/005-define-composite-chain.c
glcpp/tests/005-define-composite-chain.c.expected
glcpp/tests/006-define-composite-chain-reverse.c
glcpp/tests/006-define-composite-chain-reverse.c.expected
glcpp/tests/007-define-composite-recursive.c
glcpp/tests/007-define-composite-recursive.c.expected
glcpp/tests/008-define-empty.c
glcpp/tests/008-define-empty.c.expected
glcpp/tests/009-undef.c
glcpp/tests/009-undef.c.expected
glcpp/tests/010-undef-re-define.c
glcpp/tests/010-undef-re-define.c.expected
glcpp/tests/011-define-func-empty.c
glcpp/tests/011-define-func-empty.c.expected
glcpp/tests/012-define-func-no-args.c
glcpp/tests/012-define-func-no-args.c.expected
glcpp/tests/013-define-func-1-arg-unused.c
glcpp/tests/013-define-func-1-arg-unused.c.expected
glcpp/tests/014-define-func-2-arg-unused.c
glcpp/tests/014-define-func-2-arg-unused.c.expected
glcpp/tests/015-define-object-with-parens.c
glcpp/tests/015-define-object-with-parens.c.expected
glcpp/tests/016-define-func-1-arg.c
glcpp/tests/016-define-func-1-arg.c.expected
glcpp/tests/017-define-func-2-args.c
glcpp/tests/017-define-func-2-args.c.expected
glcpp/tests/018-define-func-macro-as-parameter.c
glcpp/tests/018-define-func-macro-as-parameter.c.expected
glcpp/tests/019-define-func-1-arg-multi.c
glcpp/tests/019-define-func-1-arg-multi.c.expected
glcpp/tests/020-define-func-2-arg-multi.c
glcpp/tests/020-define-func-2-arg-multi.c.expected
glcpp/tests/021-define-func-compose.c
glcpp/tests/021-define-func-compose.c.expected
glcpp/tests/022-define-func-arg-with-parens.c
glcpp/tests/022-define-func-arg-with-parens.c.expected
glcpp/tests/023-define-extra-whitespace.c
glcpp/tests/023-define-extra-whitespace.c.expected
glcpp/tests/024-define-chain-to-self-recursion.c
glcpp/tests/024-define-chain-to-self-recursion.c.expected
glcpp/tests/025-func-macro-as-non-macro.c
glcpp/tests/025-func-macro-as-non-macro.c.expected
glcpp/tests/026-define-func-extra-newlines.c
glcpp/tests/026-define-func-extra-newlines.c.expected
glcpp/tests/027-define-chain-obj-to-func.c
glcpp/tests/027-define-chain-obj-to-func.c.expected
glcpp/tests/028-define-chain-obj-to-non-func.c
glcpp/tests/028-define-chain-obj-to-non-func.c.expected
glcpp/tests/029-define-chain-obj-to-func-with-args.c
glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected
glcpp/tests/030-define-chain-obj-to-func-compose.c
glcpp/tests/030-define-chain-obj-to-func-compose.c.expected
glcpp/tests/031-define-chain-func-to-func-compose.c
glcpp/tests/031-define-chain-func-to-func-compose.c.expected
glcpp/tests/032-define-func-self-recurse.c
glcpp/tests/032-define-func-self-recurse.c.expected
glcpp/tests/033-define-func-self-compose.c
glcpp/tests/033-define-func-self-compose.c.expected
glcpp/tests/034-define-func-self-compose-non-func.c
glcpp/tests/034-define-func-self-compose-non-func.c.expected
glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c
glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected
glcpp/tests/036-define-func-non-macro-multi-token-argument.c
glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected
glcpp/tests/037-finalize-unexpanded-macro.c
glcpp/tests/037-finalize-unexpanded-macro.c.expected
glcpp/tests/038-func-arg-with-commas.c
glcpp/tests/038-func-arg-with-commas.c.expected
glcpp/tests/039-func-arg-obj-macro-with-comma.c
glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected
glcpp/tests/040-token-pasting.c
glcpp/tests/040-token-pasting.c.expected
glcpp/tests/041-if-0.c
glcpp/tests/041-if-0.c.expected
glcpp/tests/042-if-1.c
glcpp/tests/042-if-1.c.expected
glcpp/tests/043-if-0-else.c
glcpp/tests/043-if-0-else.c.expected
glcpp/tests/044-if-1-else.c
glcpp/tests/044-if-1-else.c.expected
glcpp/tests/045-if-0-elif.c
glcpp/tests/045-if-0-elif.c.expected
glcpp/tests/046-if-1-elsif.c
glcpp/tests/046-if-1-elsif.c.expected
glcpp/tests/047-if-elif-else.c
glcpp/tests/047-if-elif-else.c.expected
glcpp/tests/048-if-nested.c
glcpp/tests/048-if-nested.c.expected
glcpp/tests/049-if-expression-precedence.c
glcpp/tests/049-if-expression-precedence.c.expected
glcpp/tests/050-if-defined.c
glcpp/tests/050-if-defined.c.expected
glcpp/tests/051-if-relational.c
glcpp/tests/051-if-relational.c.expected
glcpp/tests/052-if-bitwise.c
glcpp/tests/052-if-bitwise.c.expected
glcpp/tests/053-if-divide-and-shift.c
glcpp/tests/053-if-divide-and-shift.c.expected
glcpp/tests/054-if-with-macros.c
glcpp/tests/054-if-with-macros.c.expected
glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c
glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected
glcpp/tests/056-macro-argument-with-comma.c
glcpp/tests/056-macro-argument-with-comma.c.expected
glcpp/tests/057-empty-arguments.c
glcpp/tests/057-empty-arguments.c.expected
glcpp/tests/058-token-pasting-empty-arguments.c
glcpp/tests/058-token-pasting-empty-arguments.c.expected
glcpp/tests/059-token-pasting-integer.c
glcpp/tests/059-token-pasting-integer.c.expected
glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c
glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected
glcpp/tests/061-define-chain-obj-to-func-multi.c
glcpp/tests/061-define-chain-obj-to-func-multi.c.expected
glcpp/tests/062-if-0-skips-garbage.c
glcpp/tests/062-if-0-skips-garbage.c.expected
glcpp/tests/063-comments.c
glcpp/tests/063-comments.c.expected
glcpp/tests/071-punctuator.c
glcpp/tests/071-punctuator.c.expected
glcpp/tests/072-token-pasting-same-line.c
glcpp/tests/072-token-pasting-same-line.c.expected
glcpp/tests/099-c99-example.c
glcpp/tests/099-c99-example.c.expected
glcpp/tests/glcpp-test
glcpp/xtalloc.c

index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..077db8d8e14f895acdfe644e7cdca6bf9a6421fb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++glcpp
++glcpp-lex.c
++glcpp-parse.c
++glcpp-parse.h
++*.o
++*~
++tests/*.out
diff --cc glcpp/Makefile
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3fb44ac3b2ed88a5ffcd4918519f2693e075a2fb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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 --cc glcpp/README
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ab42a3ffe1278b06b48a41b90576d233f69f6fdf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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).
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0d9a75415a3e62f981823e179bfc86c0e05319d3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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;
++}
++
++%%
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..807cf5950900cb34800533ee7e974a8539f18af3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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 --cc glcpp/glcpp.c
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fcdc4ed8a0f53f4d785cbb37290e39b02887172c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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 --cc glcpp/glcpp.h
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4459daa4f327cec9ed94be49ee5dc994b080608f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e89a2564d76ce125663f0328bc1c5dd5f9cdc010
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b9dd343dee9c0f44e16b2c70e2ad5e00fbda0090
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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 */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d2197342c04f9fd143bd560a24d5a0c4f4370078
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5ef39e14cc693e13a0f32a50515b8605baace289
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..696cb3a74fc2003863adb1157c5715e269fb3c3b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++this is  four         tokens
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a7fc918c90856fb2c6d8579b40afca5cb32b5cfd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++this is four tokens
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cbf2fee0e75d23a47849240023fd3e6dd221f172
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo 1
++foo
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a464d9da742a631e9d8c104a45f2e44f1629a9a1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++1
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..87d75c68751e5c60c2d0464fc032a4c68e4b5641
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define foo 1
++#define bar foo
++bar
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c6c9ee38a9e2c3187bfd8b601357d77c207e106d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++1
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a18b724eca0f899aeda03e8c021226b4648a338e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define bar foo
++#define foo 1
++bar
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c6c9ee38a9e2c3187bfd8b601357d77c207e106d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++1
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2ac56ea3dcf7bd66e31f3cdcd38c02ff87b280d0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++#define foo bar
++#define bar baz
++#define baz foo
++foo
++bar
++baz
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2d07687f8ca760ae40c66450dbef5137f11d6cd9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++
++
++
++foo
++bar
++baz
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f5521df968dd1abbbff75e1854050a46a5bbad96
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define foo 1
++#define bar a foo
++bar
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..892975c268cdd4a09a9ed894e63c64152ff22514
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++a 1
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4bb91a1221a0dc55a278e7780831b7d984d277a1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define bar a foo
++#define foo 1
++bar
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..892975c268cdd4a09a9ed894e63c64152ff22514
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++a 1
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5784565bdf3ebfea6d253e2f664dc2e686b76f7c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++#define foo a bar
++#define bar b baz
++#define baz c foo
++foo
++bar
++baz
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0b0b477d9df13d349a5a961ad3ecd6776f23925a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++
++
++
++a b c foo
++b c a bar
++c a b baz
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b1bd17ec215ff8317e503d18bd212f39b2db6160
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo
++foo
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..139597f9cb07c5d48bed18984ec4747f4b4f3438
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3fc1fb442439e0b77c2edc875e31bc99c125b9dc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++#define foo 1
++foo
++#undef foo
++foo
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9c0b35a45185933ba1e7694c55f02b3119861e02
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++
++1
++
++foo
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..32ff73798b1179608bccb8678e7430bfbac85e0f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++#define foo 1
++foo
++#undef foo
++foo
++#define foo 2
++foo
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5970f49028e3a90e7d138eaabe7ae3fb949f6f69
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++
++1
++
++foo
++
++2
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d9ce13c22843bb195236d20206e0b494f432d9e7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo()
++foo()
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..139597f9cb07c5d48bed18984ec4747f4b4f3438
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c2bb730b115d01f22a37db7cef1432c02193a708
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo() bar
++foo()
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9f075f2600465bf5fee61a599d33b35bb050e9e2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++bar
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f78fb8b118aa0c1dd1ed13487984a987f5fb98de
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(x) 1
++foo(bar)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a464d9da742a631e9d8c104a45f2e44f1629a9a1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++1
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..11feb2624b784f06d14938f35e3a1ca87e643b4e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(x,y) 1
++foo(bar,baz)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a464d9da742a631e9d8c104a45f2e44f1629a9a1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++1
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..558da9c617bdf8a3e2b33cb581e6a9c7c37d9a77
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++#define foo ()1
++foo()
++#define bar ()2
++bar()
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a70321a4c51e251adfbaac82d62be37d05073190
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++
++()1()
++
++()2()
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a2e2404c7c1e162cbb6030b7306f17d84af4ffe2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(x) ((x)+1)
++foo(bar)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6bfe04f738131244b442d059f9401608623839be
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++((bar)+1)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c7253835278f4f5eb8422281e8557563d69b5b38
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(x,y) ((x)*(y))
++foo(bar,baz)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f7a2b8c26cbff839cdbb1b870b2245c299f8ce00
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++((bar)*(baz))
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..668130b8f9b35e591c86588cdf5ed63136404559
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define x 0
++#define foo(x) x
++foo(1)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c6c9ee38a9e2c3187bfd8b601357d77c207e106d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++1
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c4e62b255088f2356b288a2b968143ec343dfda9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(x) (x)
++foo(this is more than one word)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1e89b8cfd0ca587e5f0a084bfe4ef25217ca777a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++(this is more than one word)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3049ad15465c804cb94be8a4a2c361c208ff6e4b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(x,y) x,two fish,red fish,y
++foo(one fish, blue fish)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..19f59f5ecb75daa7b97373ecabac7aa78218ace4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++one fish,two fish,red fish,blue fish
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..21ddd0e65f9986757e475a2b51be5390f2b21635
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define bar(x) (1+(x))
++#define foo(y) (2*(y))
++foo(bar(3))
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..87f51f0baca66b9080792865537ee1b0d2038a9d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++(2*((1+(3))))
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c20d73a4a28fe8083c24a34c85b2f0b37f797412
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(x) (x)
++foo(argument(including parens)for the win)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1dfc6698bb7c3af1b615872f2549ab962e0cecbf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++(argument(including parens)for the win)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7ebfed6516c6f09f11fb94945a4aa4c969ef0381
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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 ) 
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9c58275d0f9bce2d01e8a7580a5781a754d95e68
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++
++
++
++
++1
++2
++3 4
++5 6 7
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e788adce30c868a35ebe5d5d21e6ed118ef7325e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define  foo foo
++#define  bar foo
++bar
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..15600af546b0bc9b7f5c900aab4d953d3a4c68a0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++foo
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b433671d1bfd0fd04df2693ab36708748b9bcf18
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(bar) bar
++foo bar
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4a59f0520e32598bcf6e1801e88a5bf07d1885fc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++foo bar
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0d837405309c20f1fd361e6c2e5586d64da9ac7b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++#define foo(a) bar
++
++foo
++(
++1
++)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5e3c70f2cc57abdfb3635a62a5f8fd95a2153257
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++bar
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5ccb52caba5ccd7e55a03d9d1713595c7b9ac844
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define failure() success
++#define foo failure()
++foo
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..94c15f95059b5723e6a5a75203c91730586c8b73
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++success
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..44962a7187669bd28d1b6e1ab1c75c9ff5368cdb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define success() failure
++#define foo success
++foo
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..94c15f95059b5723e6a5a75203c91730586c8b73
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++success
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..261f7d28fc2dc33b005137320197a407c14c6ef1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define bar(failure) failure
++#define foo bar(success)
++foo
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..94c15f95059b5723e6a5a75203c91730586c8b73
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++success
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e56fbefd62dd4bc2b1e819ecef5ee22ca2e37789
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++#define baz(failure) failure
++#define bar(failure) failure
++#define foo bar(baz(success))
++foo
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bed826e78319597fafb1047aa0f2eccd4cf449ed
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++
++
++
++success
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3f4c8744dffbc97d82267d822c8fe8e204027f1f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++#define baz(failure) failure
++#define bar(failure) failure
++#define foo() bar(baz(success))
++foo()
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bed826e78319597fafb1047aa0f2eccd4cf449ed
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++
++
++
++success
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b3ac70f499c750b3a2509bfaac65a0b7dd24d550
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(a) foo(2*(a))
++foo(3)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..983f941740124bc0a7f8ea7b18a03283b1e91296
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++foo(2*(3))
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f65e48286cf9ed0cd31686e753e2359946d4083e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(a) foo(2*(a))
++foo(foo(3))
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..081836236430fc20aad9c92995d33f84d2db02fa
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++foo(2*(foo(2*(3))))
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..209a5f7e07c0d02c66cb2327d6e8c2c4c206be05
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(bar) bar
++foo(foo)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3f808fe665dc102e016479cb5218e9b8e4e1ef58
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++foo
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c307fbe830f7200a089ffb4c67a9c5c0bc7d9b7e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(bar) bar
++foo(1+foo)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..09dfdd64e9bcb9b583378cf0d557ae39f31d1111
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++1+foo
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b21ff336738cd6ebbd58115aca34b23c7b5aec36
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define bar success
++#define foo(x) x
++foo(more bar)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..580ed9599c5f0cf23a81bb86aee58c392ad26d86
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++more success
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b3a2f37f1b933a6ed19c836d6ae2f4c76c607dfc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define expand(x) expand(x once)
++#define foo(x) x
++foo(expand(just))
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e804d7e4f9fa7d0a65e0cf3dbf2daaf6a32021df
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++expand(just once)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1407c7d6e3c2642db1e3ff8f7c5ed2610a02d188
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define foo(x) success
++foo(argument (with,embedded , commas) -- tricky)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6544adb3a254c12173bc1cc4f7bef7f31abb1bcb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++success
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0f7fe632b56720ffdedd2bf36eadcfb4e387e815
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define foo(a) (a)
++#define bar two,words
++foo(bar)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8a15397a033d9b94c8dc58ff637e7af75ef24c4d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++(two,words)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..caab3ba736808777b6cf17abff867ca6321c89db
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define paste(a,b) a ## b
++paste(one , token)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..48e836ec3fa9a421a9cece4d321696379092cdd1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++onetoken
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2cab677d3e8e7c1385fdcb1ec9c9d4ffe59cd33f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++success_1
++#if 0
++failure
++#endif
++success_2
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8b506b32d55218362855f0c299330230cb453be0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++success_1
++
++
++
++success_2
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..874a25cf41b82e38c052c8cbd1479ffb24678e78
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++success_1
++#if 1
++success_2
++#endif
++success_3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a6ae9465a97c8d123511c15e67db03b8262e52c8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++success_1
++
++success_2
++
++success_3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..323351f9dbf57456d2a99204cb60de69405da47b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++success_1
++#if 0
++failure
++#else
++success_2
++#endif
++success_3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3d7e6be96c882e6ca58b4b4444647f3a0cffe544
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++success_1
++
++
++
++success_2
++
++success_3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..28dfc25c6f0a4678eb0fb6a61a15e2d61ba94f43
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++success_1
++#if 1
++success_2
++#else
++failure
++#endif
++success_3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4a31e1cfa9ee4a0ea65990293a2a385b9d3154b9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++success_1
++
++success_2
++
++
++
++success_3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e50f686d461a863cea30bba33d8a3e9d0bd0d21f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++success_1
++#if 0
++failure_1
++#elif 0
++failure_2
++#elif 1
++success_3
++#elif 1
++failure_3
++#endif
++success_4
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a9bb1588e4fa3523d9bce1fad9269cb9d3ef0245
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++success_1
++
++
++
++
++
++success_3
++
++
++
++success_4
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..130515a01eabc81e42bdd023af20cb947d7cd99d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++success_1
++#if 1
++success_2
++#elif 0
++failure_1
++#elif 1
++failure_2
++#elif 0
++failure_3
++#endif
++success_3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a4995713ca5e2c6e6b63b9131bb03206af1081c1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++success_1
++
++success_2
++
++
++
++
++
++
++
++success_3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e8f0838a9ed679811cf353d37360bbb2a50b4e41
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++success_1
++#if 0
++failure_1
++#elif 0
++failure_2
++#elif 0
++failure_3
++#else
++success_2
++#endif
++success_3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..54d30861197615cbec3b245357c24b8cb60e75a2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++success_1
++
++
++
++
++
++
++
++success_2
++
++success_3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fc4679c3be4676ffe7e3eeed488c6230e9fb7ee3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++success_1
++#if 0
++failure_1
++#if 1
++failure_2
++#else
++failure_3
++#endif
++failure_4
++#endif
++success_2
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8beb9c32c37985c22c7d3af6983b867bff5c85e1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++success_1
++
++
++
++
++
++
++
++
++
++success_2
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..833ea03882ac95dd9bd09c4e04f8bafe7e24d30e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++#if 1 + 2 * 3 + - (25 % 17 - + 1)
++failure with operator precedence
++#else
++success
++#endif
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..729bdd15f80a15cb800fd06956e597edd1f68f8a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++
++
++
++success
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..34f0f95140eb48be1a8011431ffb1219f2dc2dfd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..737eb8d94031f5f704079793ba51302023ff5a62
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++
++
++
++success_1
++
++
++
++success_2
++
++
++
++
++
++
++
++success_3
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c3db488e0de73690eb7bb91dce668bd916feb718
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..652fefdd43b1ce10b3a6ae3bfd9695b6d8137dee
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,35 @@@
++
++
++
++success_1
++
++
++
++success_2
++
++
++
++
++
++success_3
++
++
++
++
++
++success_3
++
++
++
++
++
++
++
++success_4
++
++
++
++success_5
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2d8e45eb61efa0ee182975f8698392f50e6982ea
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..44e52b206e5ef6c84382d6ee3d65e53c9edbf271
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,20 @@@
++
++
++
++success_1
++
++
++success_2
++
++
++
++
++
++
++success_3
++
++
++success_4
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d24c54a88d147af62eca415193b2377cc84a1be6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7e78e0454e05ebed3518fd5f6e0a4dabc41e0536
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++
++
++
++success_1
++
++
++success_2
++
++
++
++
++
++
++success_3
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3da79a0d96e547238f91f221c570daa2d6f2826d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..70f737c90a9da4e1aa60ca6ebcf0ea9f08847b7b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,34 @@@
++
++
++
++
++
++
++
++success_1
++
++
++success_2
++
++
++
++
++success_3
++
++
++
++
++success_4
++
++
++
++
++
++
++success_5
++
++
++success_6
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..00f2c2346d69229f24977cad828f9ae0c07894e5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define failure() success
++#define foo failure
++foo()
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..94c15f95059b5723e6a5a75203c91730586c8b73
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++success
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..58701d1f25b5f97cbad577509fd2f3f43453be08
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++#define bar with,embedded,commas
++#define function(x) success
++#define foo function
++foo(bar)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bed826e78319597fafb1047aa0f2eccd4cf449ed
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++
++
++
++success
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6140232865d55b64568edd2a97029512b78e8224
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++#define zero() success
++zero()
++#define one(x) success
++one()
++#define two(x,y) success
++two(,)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7d97e15e29d854a45effcb5a3a8896f9000bd64b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++
++success
++
++success
++
++success
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8ac260c76b671a451603eaf3f6e8dedca2ffc1e6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++#define paste(x,y) x ## y
++paste(a,b)
++paste(a,)
++paste(,b)
++paste(,)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e0967a1b9519f0294579d94391ca06062d2ccb55
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++
++ab
++a
++b
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..37b895a42378cbabd4dd1515f017e6f70f18845f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++#define paste(x,y) x ## y
++paste(1,2)
++paste(1,000)
++paste(identifier,2)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f1288aa7cb749a0c30d9f48f8b8b50b09b03ddc5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++
++12
++1000
++identifier2
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ed80ea879ceaea19a677775249e52394439a144c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++#define double(a) a*2
++#define foo double(
++foo 5)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3e5501aa6e82c520f9d6647197221493df035231
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,3 @@@
++
++
++5*2
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6dbfd1f62d1e1f6ee7eef8127feb1ebcfec264be
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++#define foo(x) success
++#define bar foo
++#define baz bar
++#define joe baz
++joe (failure)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..15eb64b97f19456d5bcd1eda35f1c65dbfd6cce9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++
++
++
++
++success
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d9e439bb890627f2f9541d0fa55b6f652676da50
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++#define foo(a,b)
++#if 0
++foo(bar)
++foo(
++#endif
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3f2ff2d6cc8f257ffcade7ead1ca4042c0e884b9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++
++
++
++
++
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e641d2f0f9ee5b6b060de7547ef924a7d79f9175
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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 */
++/*/*/
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4998d76cc227395ad3c3d7ac4548020dee1b64dc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,13 @@@
++ 
++
++
++f = g /h;
++ l();
++m = n
+++ p;
++ 
++more code here
++ 
++are not treated like comments.
++ 
++ 
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..959d68259884391711c665818508fb75cd2fac72
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++a = b
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..959d68259884391711c665818508fb75cd2fac72
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++a = b
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e421e9d5e298d79de261b88bbc89c48130d2b7e0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++#define paste(x) success_ ## x
++paste(1) paste(2) paste(3)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7b80af7e465b0b868c64130099c16b2d20571a63
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++
++success_1 success_2 success_3
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d1976b1f26561b2c9c7fb382383b36736ed8bd46
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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(,)};
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..352bbff48f5a3cbcd281dec510bf72974134386c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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, };
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..396f6e175e8eaa31d39711b6d20ea360a11480c2
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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 --cc glcpp/xtalloc.c
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..656ac2d6cb5bff989f62462fff0e147432e643d2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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;
++}