From: Kenneth Graunke Date: Mon, 21 Jun 2010 18:22:11 +0000 (-0700) Subject: Merge Carl's preprocessor into the glcpp subdirectory. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6f510a49d2f3271432844d6b7e2bfe459b2126d4;p=mesa.git Merge Carl's preprocessor into the glcpp subdirectory. --- 6f510a49d2f3271432844d6b7e2bfe459b2126d4 diff --cc glcpp/.gitignore index 00000000000,00000000000..077db8d8e14 new file mode 100644 --- /dev/null +++ b/glcpp/.gitignore @@@ -1,0 -1,0 +1,7 @@@ ++glcpp ++glcpp-lex.c ++glcpp-parse.c ++glcpp-parse.h ++*.o ++*~ ++tests/*.out diff --cc glcpp/Makefile index 00000000000,00000000000..3fb44ac3b2e new file mode 100644 --- /dev/null +++ b/glcpp/Makefile @@@ -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 00000000000,00000000000..ab42a3ffe12 new file mode 100644 --- /dev/null +++ b/glcpp/README @@@ -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). diff --cc glcpp/glcpp-lex.l index 00000000000,00000000000..0d9a75415a3 new file mode 100644 --- /dev/null +++ b/glcpp/glcpp-lex.l @@@ -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 ++#include ++ ++#include "glcpp.h" ++#include "glcpp-parse.h" ++%} ++ ++%option reentrant noyywrap ++%option extra-type="glcpp_parser_t *" ++ ++SPACE [[:space:]] ++NONSPACE [^[:space:]] ++NEWLINE [\n] ++HSPACE [ \t] ++HASH ^{HSPACE}*#{HSPACE}* ++IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]* ++PUNCTUATION [][(){}.&*~!/%<>^|;,=+-] ++OTHER [^][(){}.&*~!/%<>^|;,=#[:space:]+-]+ ++ ++DECIMAL_INTEGER [1-9][0-9]*[uU]? ++OCTAL_INTEGER 0[0-7]*[uU]? ++HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]? ++ ++NON_STARS_THEN_STARS [^*]*[*]+ ++ ++%% ++ ++ /* Single-line comments */ ++"//"[^\n]+\n { ++ return NEWLINE; ++} ++ ++ /* Multi-line comments */ ++"/*"({NON_STARS_THEN_STARS}[^*/])*{NON_STARS_THEN_STARS}"/" { ++ if (yyextra->space_tokens) ++ return SPACE; ++} ++ ++{HASH}if/.*\n { ++ yyextra->lexing_if = 1; ++ yyextra->space_tokens = 0; ++ return HASH_IF; ++} ++ ++{HASH}elif/.*\n { ++ yyextra->lexing_if = 1; ++ yyextra->space_tokens = 0; ++ return HASH_ELIF; ++} ++ ++{HASH}else/.*\n { ++ yyextra->space_tokens = 0; ++ return HASH_ELSE; ++} ++ ++{HASH}endif/.*\n { ++ yyextra->space_tokens = 0; ++ return HASH_ENDIF; ++} ++ ++ /* When skipping (due to an #if 0 or similar) consume anything ++ * up to a newline. We do this less priroty than any ++ * #if-related directive (#if, #elif, #else, #endif), but with ++ * more priority than any other directive or token to avoid ++ * any side-effects from skipped content. ++ * ++ * We use the lexing_if flag to avoid skipping any part of an ++ * if conditional expression. */ ++[^\n]+/\n { ++ if (yyextra->lexing_if || ++ yyextra->skip_stack == NULL || ++ yyextra->skip_stack->type == SKIP_NO_SKIP) ++ { ++ REJECT; ++ } ++} ++ ++{HASH}define{HSPACE}+/{IDENTIFIER}"(" { ++ yyextra->space_tokens = 0; ++ return HASH_DEFINE_FUNC; ++} ++ ++{HASH}define { ++ yyextra->space_tokens = 0; ++ return HASH_DEFINE_OBJ; ++} ++ ++{HASH}undef { ++ yyextra->space_tokens = 0; ++ return HASH_UNDEF; ++} ++ ++{HASH} { ++ yyextra->space_tokens = 0; ++ return HASH; ++} ++ ++{DECIMAL_INTEGER} { ++ yylval.str = xtalloc_strdup (yyextra, yytext); ++ return INTEGER_STRING; ++} ++ ++{OCTAL_INTEGER} { ++ yylval.str = xtalloc_strdup (yyextra, yytext); ++ return INTEGER_STRING; ++} ++ ++{HEXADECIMAL_INTEGER} { ++ yylval.str = xtalloc_strdup (yyextra, yytext); ++ return INTEGER_STRING; ++} ++ ++"<<" { ++ return LEFT_SHIFT; ++} ++ ++">>" { ++ return RIGHT_SHIFT; ++} ++ ++"<=" { ++ return LESS_OR_EQUAL; ++} ++ ++">=" { ++ return GREATER_OR_EQUAL; ++} ++ ++"==" { ++ return EQUAL; ++} ++ ++"!=" { ++ return NOT_EQUAL; ++} ++ ++"&&" { ++ return AND; ++} ++ ++"||" { ++ return OR; ++} ++ ++"##" { ++ return PASTE; ++} ++ ++"defined" { ++ return DEFINED; ++} ++ ++{IDENTIFIER} { ++ yylval.str = xtalloc_strdup (yyextra, yytext); ++ return IDENTIFIER; ++} ++ ++{PUNCTUATION} { ++ return yytext[0]; ++} ++ ++{OTHER}+ { ++ yylval.str = xtalloc_strdup (yyextra, yytext); ++ return OTHER; ++} ++ ++{HSPACE}+ { ++ if (yyextra->space_tokens) { ++ return SPACE; ++ } ++} ++ ++\n { ++ yyextra->lexing_if = 0; ++ return NEWLINE; ++} ++ ++%% diff --cc glcpp/glcpp-parse.y index 00000000000,00000000000..807cf595090 new file mode 100644 --- /dev/null +++ b/glcpp/glcpp-parse.y @@@ -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 ++#include ++#include ++#include ++ ++#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 expression INTEGER operator SPACE ++%type IDENTIFIER INTEGER_STRING OTHER ++%type identifier_list ++%type preprocessing_token ++%type 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, ++ ¶meter_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 00000000000,00000000000..fcdc4ed8a0f new file mode 100644 --- /dev/null +++ b/glcpp/glcpp.c @@@ -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 00000000000,00000000000..4459daa4f32 new file mode 100644 --- /dev/null +++ b/glcpp/glcpp.h @@@ -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 ++ ++#include ++ ++#include "hash_table.h" ++ ++#define yyscan_t void* ++ ++/* Some data types used for parser values. */ ++ ++typedef struct string_node { ++ const char *str; ++ struct string_node *next; ++} string_node_t; ++ ++typedef struct string_list { ++ string_node_t *head; ++ string_node_t *tail; ++} string_list_t; ++ ++typedef struct token token_t; ++typedef struct token_list token_list_t; ++ ++typedef union YYSTYPE ++{ ++ intmax_t ival; ++ char *str; ++ string_list_t *string_list; ++ token_t *token; ++ token_list_t *token_list; ++} YYSTYPE; ++ ++# define YYSTYPE_IS_TRIVIAL 1 ++# define YYSTYPE_IS_DECLARED 1 ++ ++struct token { ++ int type; ++ YYSTYPE value; ++}; ++ ++typedef struct token_node { ++ token_t *token; ++ struct token_node *next; ++} token_node_t; ++ ++struct token_list { ++ token_node_t *head; ++ token_node_t *tail; ++ token_node_t *non_space_tail; ++}; ++ ++typedef struct argument_node { ++ token_list_t *argument; ++ struct argument_node *next; ++} argument_node_t; ++ ++typedef struct argument_list { ++ argument_node_t *head; ++ argument_node_t *tail; ++} argument_list_t; ++ ++typedef struct glcpp_parser glcpp_parser_t; ++ ++typedef enum { ++ TOKEN_CLASS_IDENTIFIER, ++ TOKEN_CLASS_IDENTIFIER_FINALIZED, ++ TOKEN_CLASS_FUNC_MACRO, ++ TOKEN_CLASS_OBJ_MACRO ++} token_class_t; ++ ++token_class_t ++glcpp_parser_classify_token (glcpp_parser_t *parser, ++ const char *identifier, ++ int *parameter_index); ++ ++typedef struct { ++ int is_function; ++ string_list_t *parameters; ++ const char *identifier; ++ token_list_t *replacements; ++} macro_t; ++ ++typedef struct expansion_node { ++ macro_t *macro; ++ token_node_t *replacements; ++ struct expansion_node *next; ++} expansion_node_t; ++ ++typedef enum skip_type { ++ SKIP_NO_SKIP, ++ SKIP_TO_ELSE, ++ SKIP_TO_ENDIF ++} skip_type_t; ++ ++typedef struct skip_node { ++ skip_type_t type; ++ struct skip_node *next; ++} skip_node_t; ++ ++typedef struct active_list { ++ const char *identifier; ++ token_node_t *marker; ++ struct active_list *next; ++} active_list_t; ++ ++struct glcpp_parser { ++ yyscan_t scanner; ++ struct hash_table *defines; ++ active_list_t *active; ++ int lexing_if; ++ int space_tokens; ++ int newline_as_space; ++ int in_control_line; ++ int paren_count; ++ skip_node_t *skip_stack; ++ token_list_t *lex_from_list; ++ token_node_t *lex_from_node; ++}; ++ ++glcpp_parser_t * ++glcpp_parser_create (void); ++ ++int ++glcpp_parser_parse (glcpp_parser_t *parser); ++ ++void ++glcpp_parser_destroy (glcpp_parser_t *parser); ++ ++/* Generated by glcpp-lex.l to glcpp-lex.c */ ++ ++int ++glcpp_lex_init_extra (glcpp_parser_t *parser, yyscan_t* scanner); ++ ++int ++glcpp_lex (yyscan_t scanner); ++ ++int ++glcpp_lex_destroy (yyscan_t scanner); ++ ++/* Generated by glcpp-parse.y to glcpp-parse.c */ ++ ++int ++yyparse (glcpp_parser_t *parser); ++ ++/* xtalloc - wrappers around talloc to check for out-of-memory */ ++ ++#define xtalloc(ctx, type) (type *)xtalloc_named_const(ctx, sizeof(type), #type) ++ ++#define xtalloc_size(ctx, size) xtalloc_named_const(ctx, size, __location__) ++ ++void * ++xtalloc_named_const (const void *context, size_t size, const char *name); ++ ++char * ++xtalloc_strdup (const void *t, const char *p); ++ ++char * ++xtalloc_strndup (const void *t, const char *p, size_t n); ++ ++char * ++xtalloc_asprintf (const void *t, const char *fmt, ...); ++ ++void * ++_xtalloc_reference_loc (const void *context, ++ const void *ptr, const char *location); ++ ++#define xtalloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_xtalloc_reference_loc((ctx),(ptr), __location__) ++ ++#endif diff --cc glcpp/hash_table.c index 00000000000,00000000000..e89a2564d76 new file mode 100644 --- /dev/null +++ b/glcpp/hash_table.c @@@ -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 ++ */ ++ ++#include "main/imports.h" ++#include "main/simple_list.h" ++#include "hash_table.h" ++ ++struct node { ++ struct node *next; ++ struct node *prev; ++}; ++ ++struct hash_table { ++ hash_func_t hash; ++ hash_compare_func_t compare; ++ ++ unsigned num_buckets; ++ struct node buckets[1]; ++}; ++ ++ ++struct hash_node { ++ struct node link; ++ const void *key; ++ void *data; ++}; ++ ++ ++struct hash_table * ++hash_table_ctor(unsigned num_buckets, hash_func_t hash, ++ hash_compare_func_t compare) ++{ ++ struct hash_table *ht; ++ unsigned i; ++ ++ ++ if (num_buckets < 16) { ++ num_buckets = 16; ++ } ++ ++ ht = _mesa_malloc(sizeof(*ht) + ((num_buckets - 1) ++ * sizeof(ht->buckets[0]))); ++ if (ht != NULL) { ++ ht->hash = hash; ++ ht->compare = compare; ++ ht->num_buckets = num_buckets; ++ ++ for (i = 0; i < num_buckets; i++) { ++ make_empty_list(& ht->buckets[i]); ++ } ++ } ++ ++ return ht; ++} ++ ++ ++void ++hash_table_dtor(struct hash_table *ht) ++{ ++ hash_table_clear(ht); ++ _mesa_free(ht); ++} ++ ++ ++void ++hash_table_clear(struct hash_table *ht) ++{ ++ struct node *node; ++ struct node *temp; ++ unsigned i; ++ ++ ++ for (i = 0; i < ht->num_buckets; i++) { ++ foreach_s(node, temp, & ht->buckets[i]) { ++ remove_from_list(node); ++ _mesa_free(node); ++ } ++ ++ assert(is_empty_list(& ht->buckets[i])); ++ } ++} ++ ++ ++void * ++hash_table_find(struct hash_table *ht, const void *key) ++{ ++ const unsigned hash_value = (*ht->hash)(key); ++ const unsigned bucket = hash_value % ht->num_buckets; ++ struct node *node; ++ ++ foreach(node, & ht->buckets[bucket]) { ++ struct hash_node *hn = (struct hash_node *) node; ++ ++ if ((*ht->compare)(hn->key, key) == 0) { ++ return hn->data; ++ } ++ } ++ ++ return NULL; ++} ++ ++ ++void ++hash_table_insert(struct hash_table *ht, void *data, const void *key) ++{ ++ const unsigned hash_value = (*ht->hash)(key); ++ const unsigned bucket = hash_value % ht->num_buckets; ++ struct hash_node *node; ++ ++ node = _mesa_calloc(sizeof(*node)); ++ ++ node->data = data; ++ node->key = key; ++ ++ insert_at_head(& ht->buckets[bucket], & node->link); ++} ++ ++ ++unsigned ++hash_table_string_hash(const void *key) ++{ ++ const char *str = (const char *) key; ++ unsigned hash = 5381; ++ ++ ++ while (*str != '\0') { ++ hash = (hash * 33) + *str; ++ str++; ++ } ++ ++ return hash; ++} diff --cc glcpp/hash_table.h index 00000000000,00000000000..b9dd343dee9 new file mode 100644 --- /dev/null +++ b/glcpp/hash_table.h @@@ -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 ++ */ ++ ++#ifndef HASH_TABLE_H ++#define HASH_TABLE_H ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include ++ ++struct hash_table; ++ ++typedef unsigned (*hash_func_t)(const void *key); ++typedef int (*hash_compare_func_t)(const void *key1, const void *key2); ++ ++/** ++ * Hash table constructor ++ * ++ * Creates a hash table with the specified number of buckets. The supplied ++ * \c hash and \c compare routines are used when adding elements to the table ++ * and when searching for elements in the table. ++ * ++ * \param num_buckets Number of buckets (bins) in the hash table. ++ * \param hash Function used to compute hash value of input keys. ++ * \param compare Function used to compare keys. ++ */ ++extern struct hash_table *hash_table_ctor(unsigned num_buckets, ++ hash_func_t hash, hash_compare_func_t compare); ++ ++ ++/** ++ * Release all memory associated with a hash table ++ * ++ * \warning ++ * This function cannot release memory occupied either by keys or data. ++ */ ++extern void hash_table_dtor(struct hash_table *ht); ++ ++ ++/** ++ * Flush all entries from a hash table ++ * ++ * \param ht Table to be cleared of its entries. ++ */ ++extern void hash_table_clear(struct hash_table *ht); ++ ++ ++/** ++ * Search a hash table for a specific element ++ * ++ * \param ht Table to be searched ++ * \param key Key of the desired element ++ * ++ * \return ++ * The \c data value supplied to \c hash_table_insert when the element with ++ * the matching key was added. If no matching key exists in the table, ++ * \c NULL is returned. ++ */ ++extern void *hash_table_find(struct hash_table *ht, const void *key); ++ ++ ++/** ++ * Add an element to a hash table ++ */ ++extern void hash_table_insert(struct hash_table *ht, void *data, ++ const void *key); ++ ++ ++/** ++ * Compute hash value of a string ++ * ++ * Computes the hash value of a string using the DJB2 algorithm developed by ++ * Professor Daniel J. Bernstein. It was published on comp.lang.c once upon ++ * a time. I was unable to find the original posting in the archives. ++ * ++ * \param key Pointer to a NUL terminated string to be hashed. ++ * ++ * \sa hash_table_string_compare ++ */ ++extern unsigned hash_table_string_hash(const void *key); ++ ++ ++/** ++ * Compare two strings used as keys ++ * ++ * This is just a macro wrapper around \c strcmp. ++ * ++ * \sa hash_table_string_hash ++ */ ++#define hash_table_string_compare ((hash_compare_func_t) strcmp) ++ ++#ifdef __cplusplus ++}; ++#endif ++ ++#endif /* HASH_TABLE_H */ diff --cc glcpp/main/imports.h index 00000000000,00000000000..d2197342c04 new file mode 100644 --- /dev/null +++ b/glcpp/main/imports.h @@@ -1,0 -1,0 +1,6 @@@ ++#include ++#include ++ ++#define _mesa_malloc(x) malloc(x) ++#define _mesa_free(x) free(x) ++#define _mesa_calloc(x) calloc(1,x) diff --cc glcpp/main/simple_list.h index 00000000000,00000000000..5ef39e14cc6 new file mode 100644 --- /dev/null +++ b/glcpp/main/simple_list.h @@@ -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 diff --cc glcpp/tests/000-content-with-spaces.c index 00000000000,00000000000..696cb3a74fc new file mode 100644 --- /dev/null +++ b/glcpp/tests/000-content-with-spaces.c @@@ -1,0 -1,0 +1,1 @@@ ++this is four tokens diff --cc glcpp/tests/000-content-with-spaces.c.expected index 00000000000,00000000000..a7fc918c908 new file mode 100644 --- /dev/null +++ b/glcpp/tests/000-content-with-spaces.c.expected @@@ -1,0 -1,0 +1,1 @@@ ++this is four tokens diff --cc glcpp/tests/001-define.c index 00000000000,00000000000..cbf2fee0e75 new file mode 100644 --- /dev/null +++ b/glcpp/tests/001-define.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo 1 ++foo diff --cc glcpp/tests/001-define.c.expected index 00000000000,00000000000..a464d9da742 new file mode 100644 --- /dev/null +++ b/glcpp/tests/001-define.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++1 diff --cc glcpp/tests/002-define-chain.c index 00000000000,00000000000..87d75c68751 new file mode 100644 --- /dev/null +++ b/glcpp/tests/002-define-chain.c @@@ -1,0 -1,0 +1,3 @@@ ++#define foo 1 ++#define bar foo ++bar diff --cc glcpp/tests/002-define-chain.c.expected index 00000000000,00000000000..c6c9ee38a9e new file mode 100644 --- /dev/null +++ b/glcpp/tests/002-define-chain.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++1 diff --cc glcpp/tests/003-define-chain-reverse.c index 00000000000,00000000000..a18b724eca0 new file mode 100644 --- /dev/null +++ b/glcpp/tests/003-define-chain-reverse.c @@@ -1,0 -1,0 +1,3 @@@ ++#define bar foo ++#define foo 1 ++bar diff --cc glcpp/tests/003-define-chain-reverse.c.expected index 00000000000,00000000000..c6c9ee38a9e new file mode 100644 --- /dev/null +++ b/glcpp/tests/003-define-chain-reverse.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++1 diff --cc glcpp/tests/004-define-recursive.c index 00000000000,00000000000..2ac56ea3dcf new file mode 100644 --- /dev/null +++ b/glcpp/tests/004-define-recursive.c @@@ -1,0 -1,0 +1,6 @@@ ++#define foo bar ++#define bar baz ++#define baz foo ++foo ++bar ++baz diff --cc glcpp/tests/004-define-recursive.c.expected index 00000000000,00000000000..2d07687f8ca new file mode 100644 --- /dev/null +++ b/glcpp/tests/004-define-recursive.c.expected @@@ -1,0 -1,0 +1,6 @@@ ++ ++ ++ ++foo ++bar ++baz diff --cc glcpp/tests/005-define-composite-chain.c index 00000000000,00000000000..f5521df968d new file mode 100644 --- /dev/null +++ b/glcpp/tests/005-define-composite-chain.c @@@ -1,0 -1,0 +1,3 @@@ ++#define foo 1 ++#define bar a foo ++bar diff --cc glcpp/tests/005-define-composite-chain.c.expected index 00000000000,00000000000..892975c268c new file mode 100644 --- /dev/null +++ b/glcpp/tests/005-define-composite-chain.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++a 1 diff --cc glcpp/tests/006-define-composite-chain-reverse.c index 00000000000,00000000000..4bb91a1221a new file mode 100644 --- /dev/null +++ b/glcpp/tests/006-define-composite-chain-reverse.c @@@ -1,0 -1,0 +1,3 @@@ ++#define bar a foo ++#define foo 1 ++bar diff --cc glcpp/tests/006-define-composite-chain-reverse.c.expected index 00000000000,00000000000..892975c268c new file mode 100644 --- /dev/null +++ b/glcpp/tests/006-define-composite-chain-reverse.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++a 1 diff --cc glcpp/tests/007-define-composite-recursive.c index 00000000000,00000000000..5784565bdf3 new file mode 100644 --- /dev/null +++ b/glcpp/tests/007-define-composite-recursive.c @@@ -1,0 -1,0 +1,6 @@@ ++#define foo a bar ++#define bar b baz ++#define baz c foo ++foo ++bar ++baz diff --cc glcpp/tests/007-define-composite-recursive.c.expected index 00000000000,00000000000..0b0b477d9df new file mode 100644 --- /dev/null +++ b/glcpp/tests/007-define-composite-recursive.c.expected @@@ -1,0 -1,0 +1,6 @@@ ++ ++ ++ ++a b c foo ++b c a bar ++c a b baz diff --cc glcpp/tests/008-define-empty.c index 00000000000,00000000000..b1bd17ec215 new file mode 100644 --- /dev/null +++ b/glcpp/tests/008-define-empty.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo ++foo diff --cc glcpp/tests/008-define-empty.c.expected index 00000000000,00000000000..139597f9cb0 new file mode 100644 --- /dev/null +++ b/glcpp/tests/008-define-empty.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++ diff --cc glcpp/tests/009-undef.c index 00000000000,00000000000..3fc1fb44243 new file mode 100644 --- /dev/null +++ b/glcpp/tests/009-undef.c @@@ -1,0 -1,0 +1,4 @@@ ++#define foo 1 ++foo ++#undef foo ++foo diff --cc glcpp/tests/009-undef.c.expected index 00000000000,00000000000..9c0b35a4518 new file mode 100644 --- /dev/null +++ b/glcpp/tests/009-undef.c.expected @@@ -1,0 -1,0 +1,4 @@@ ++ ++1 ++ ++foo diff --cc glcpp/tests/010-undef-re-define.c index 00000000000,00000000000..32ff73798b1 new file mode 100644 --- /dev/null +++ b/glcpp/tests/010-undef-re-define.c @@@ -1,0 -1,0 +1,6 @@@ ++#define foo 1 ++foo ++#undef foo ++foo ++#define foo 2 ++foo diff --cc glcpp/tests/010-undef-re-define.c.expected index 00000000000,00000000000..5970f49028e new file mode 100644 --- /dev/null +++ b/glcpp/tests/010-undef-re-define.c.expected @@@ -1,0 -1,0 +1,6 @@@ ++ ++1 ++ ++foo ++ ++2 diff --cc glcpp/tests/011-define-func-empty.c index 00000000000,00000000000..d9ce13c2284 new file mode 100644 --- /dev/null +++ b/glcpp/tests/011-define-func-empty.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo() ++foo() diff --cc glcpp/tests/011-define-func-empty.c.expected index 00000000000,00000000000..139597f9cb0 new file mode 100644 --- /dev/null +++ b/glcpp/tests/011-define-func-empty.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++ diff --cc glcpp/tests/012-define-func-no-args.c index 00000000000,00000000000..c2bb730b115 new file mode 100644 --- /dev/null +++ b/glcpp/tests/012-define-func-no-args.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo() bar ++foo() diff --cc glcpp/tests/012-define-func-no-args.c.expected index 00000000000,00000000000..9f075f26004 new file mode 100644 --- /dev/null +++ b/glcpp/tests/012-define-func-no-args.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++bar diff --cc glcpp/tests/013-define-func-1-arg-unused.c index 00000000000,00000000000..f78fb8b118a new file mode 100644 --- /dev/null +++ b/glcpp/tests/013-define-func-1-arg-unused.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(x) 1 ++foo(bar) diff --cc glcpp/tests/013-define-func-1-arg-unused.c.expected index 00000000000,00000000000..a464d9da742 new file mode 100644 --- /dev/null +++ b/glcpp/tests/013-define-func-1-arg-unused.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++1 diff --cc glcpp/tests/014-define-func-2-arg-unused.c index 00000000000,00000000000..11feb2624b7 new file mode 100644 --- /dev/null +++ b/glcpp/tests/014-define-func-2-arg-unused.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(x,y) 1 ++foo(bar,baz) diff --cc glcpp/tests/014-define-func-2-arg-unused.c.expected index 00000000000,00000000000..a464d9da742 new file mode 100644 --- /dev/null +++ b/glcpp/tests/014-define-func-2-arg-unused.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++1 diff --cc glcpp/tests/015-define-object-with-parens.c index 00000000000,00000000000..558da9c617b new file mode 100644 --- /dev/null +++ b/glcpp/tests/015-define-object-with-parens.c @@@ -1,0 -1,0 +1,4 @@@ ++#define foo ()1 ++foo() ++#define bar ()2 ++bar() diff --cc glcpp/tests/015-define-object-with-parens.c.expected index 00000000000,00000000000..a70321a4c51 new file mode 100644 --- /dev/null +++ b/glcpp/tests/015-define-object-with-parens.c.expected @@@ -1,0 -1,0 +1,4 @@@ ++ ++()1() ++ ++()2() diff --cc glcpp/tests/016-define-func-1-arg.c index 00000000000,00000000000..a2e2404c7c1 new file mode 100644 --- /dev/null +++ b/glcpp/tests/016-define-func-1-arg.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(x) ((x)+1) ++foo(bar) diff --cc glcpp/tests/016-define-func-1-arg.c.expected index 00000000000,00000000000..6bfe04f7381 new file mode 100644 --- /dev/null +++ b/glcpp/tests/016-define-func-1-arg.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++((bar)+1) diff --cc glcpp/tests/017-define-func-2-args.c index 00000000000,00000000000..c7253835278 new file mode 100644 --- /dev/null +++ b/glcpp/tests/017-define-func-2-args.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(x,y) ((x)*(y)) ++foo(bar,baz) diff --cc glcpp/tests/017-define-func-2-args.c.expected index 00000000000,00000000000..f7a2b8c26cb new file mode 100644 --- /dev/null +++ b/glcpp/tests/017-define-func-2-args.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++((bar)*(baz)) diff --cc glcpp/tests/018-define-func-macro-as-parameter.c index 00000000000,00000000000..668130b8f9b new file mode 100644 --- /dev/null +++ b/glcpp/tests/018-define-func-macro-as-parameter.c @@@ -1,0 -1,0 +1,3 @@@ ++#define x 0 ++#define foo(x) x ++foo(1) diff --cc glcpp/tests/018-define-func-macro-as-parameter.c.expected index 00000000000,00000000000..c6c9ee38a9e new file mode 100644 --- /dev/null +++ b/glcpp/tests/018-define-func-macro-as-parameter.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++1 diff --cc glcpp/tests/019-define-func-1-arg-multi.c index 00000000000,00000000000..c4e62b25508 new file mode 100644 --- /dev/null +++ b/glcpp/tests/019-define-func-1-arg-multi.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(x) (x) ++foo(this is more than one word) diff --cc glcpp/tests/019-define-func-1-arg-multi.c.expected index 00000000000,00000000000..1e89b8cfd0c new file mode 100644 --- /dev/null +++ b/glcpp/tests/019-define-func-1-arg-multi.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++(this is more than one word) diff --cc glcpp/tests/020-define-func-2-arg-multi.c index 00000000000,00000000000..3049ad15465 new file mode 100644 --- /dev/null +++ b/glcpp/tests/020-define-func-2-arg-multi.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(x,y) x,two fish,red fish,y ++foo(one fish, blue fish) diff --cc glcpp/tests/020-define-func-2-arg-multi.c.expected index 00000000000,00000000000..19f59f5ecb7 new file mode 100644 --- /dev/null +++ b/glcpp/tests/020-define-func-2-arg-multi.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++one fish,two fish,red fish,blue fish diff --cc glcpp/tests/021-define-func-compose.c index 00000000000,00000000000..21ddd0e65f9 new file mode 100644 --- /dev/null +++ b/glcpp/tests/021-define-func-compose.c @@@ -1,0 -1,0 +1,3 @@@ ++#define bar(x) (1+(x)) ++#define foo(y) (2*(y)) ++foo(bar(3)) diff --cc glcpp/tests/021-define-func-compose.c.expected index 00000000000,00000000000..87f51f0baca new file mode 100644 --- /dev/null +++ b/glcpp/tests/021-define-func-compose.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++(2*((1+(3)))) diff --cc glcpp/tests/022-define-func-arg-with-parens.c index 00000000000,00000000000..c20d73a4a28 new file mode 100644 --- /dev/null +++ b/glcpp/tests/022-define-func-arg-with-parens.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(x) (x) ++foo(argument(including parens)for the win) diff --cc glcpp/tests/022-define-func-arg-with-parens.c.expected index 00000000000,00000000000..1dfc6698bb7 new file mode 100644 --- /dev/null +++ b/glcpp/tests/022-define-func-arg-with-parens.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++(argument(including parens)for the win) diff --cc glcpp/tests/023-define-extra-whitespace.c index 00000000000,00000000000..7ebfed6516c new file mode 100644 --- /dev/null +++ b/glcpp/tests/023-define-extra-whitespace.c @@@ -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 ) diff --cc glcpp/tests/023-define-extra-whitespace.c.expected index 00000000000,00000000000..9c58275d0f9 new file mode 100644 --- /dev/null +++ b/glcpp/tests/023-define-extra-whitespace.c.expected @@@ -1,0 -1,0 +1,8 @@@ ++ ++ ++ ++ ++1 ++2 ++3 4 ++5 6 7 diff --cc glcpp/tests/024-define-chain-to-self-recursion.c index 00000000000,00000000000..e788adce30c new file mode 100644 --- /dev/null +++ b/glcpp/tests/024-define-chain-to-self-recursion.c @@@ -1,0 -1,0 +1,3 @@@ ++#define foo foo ++#define bar foo ++bar diff --cc glcpp/tests/024-define-chain-to-self-recursion.c.expected index 00000000000,00000000000..15600af546b new file mode 100644 --- /dev/null +++ b/glcpp/tests/024-define-chain-to-self-recursion.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++foo diff --cc glcpp/tests/025-func-macro-as-non-macro.c index 00000000000,00000000000..b433671d1bf new file mode 100644 --- /dev/null +++ b/glcpp/tests/025-func-macro-as-non-macro.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(bar) bar ++foo bar diff --cc glcpp/tests/025-func-macro-as-non-macro.c.expected index 00000000000,00000000000..4a59f0520e3 new file mode 100644 --- /dev/null +++ b/glcpp/tests/025-func-macro-as-non-macro.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++foo bar diff --cc glcpp/tests/026-define-func-extra-newlines.c index 00000000000,00000000000..0d837405309 new file mode 100644 --- /dev/null +++ b/glcpp/tests/026-define-func-extra-newlines.c @@@ -1,0 -1,0 +1,6 @@@ ++#define foo(a) bar ++ ++foo ++( ++1 ++) diff --cc glcpp/tests/026-define-func-extra-newlines.c.expected index 00000000000,00000000000..5e3c70f2cc5 new file mode 100644 --- /dev/null +++ b/glcpp/tests/026-define-func-extra-newlines.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++bar diff --cc glcpp/tests/027-define-chain-obj-to-func.c index 00000000000,00000000000..5ccb52caba5 new file mode 100644 --- /dev/null +++ b/glcpp/tests/027-define-chain-obj-to-func.c @@@ -1,0 -1,0 +1,3 @@@ ++#define failure() success ++#define foo failure() ++foo diff --cc glcpp/tests/027-define-chain-obj-to-func.c.expected index 00000000000,00000000000..94c15f95059 new file mode 100644 --- /dev/null +++ b/glcpp/tests/027-define-chain-obj-to-func.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++success diff --cc glcpp/tests/028-define-chain-obj-to-non-func.c index 00000000000,00000000000..44962a71876 new file mode 100644 --- /dev/null +++ b/glcpp/tests/028-define-chain-obj-to-non-func.c @@@ -1,0 -1,0 +1,3 @@@ ++#define success() failure ++#define foo success ++foo diff --cc glcpp/tests/028-define-chain-obj-to-non-func.c.expected index 00000000000,00000000000..94c15f95059 new file mode 100644 --- /dev/null +++ b/glcpp/tests/028-define-chain-obj-to-non-func.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++success diff --cc glcpp/tests/029-define-chain-obj-to-func-with-args.c index 00000000000,00000000000..261f7d28fc2 new file mode 100644 --- /dev/null +++ b/glcpp/tests/029-define-chain-obj-to-func-with-args.c @@@ -1,0 -1,0 +1,3 @@@ ++#define bar(failure) failure ++#define foo bar(success) ++foo diff --cc glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected index 00000000000,00000000000..94c15f95059 new file mode 100644 --- /dev/null +++ b/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++success diff --cc glcpp/tests/030-define-chain-obj-to-func-compose.c index 00000000000,00000000000..e56fbefd62d new file mode 100644 --- /dev/null +++ b/glcpp/tests/030-define-chain-obj-to-func-compose.c @@@ -1,0 -1,0 +1,4 @@@ ++#define baz(failure) failure ++#define bar(failure) failure ++#define foo bar(baz(success)) ++foo diff --cc glcpp/tests/030-define-chain-obj-to-func-compose.c.expected index 00000000000,00000000000..bed826e7831 new file mode 100644 --- /dev/null +++ b/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected @@@ -1,0 -1,0 +1,4 @@@ ++ ++ ++ ++success diff --cc glcpp/tests/031-define-chain-func-to-func-compose.c index 00000000000,00000000000..3f4c8744dff new file mode 100644 --- /dev/null +++ b/glcpp/tests/031-define-chain-func-to-func-compose.c @@@ -1,0 -1,0 +1,4 @@@ ++#define baz(failure) failure ++#define bar(failure) failure ++#define foo() bar(baz(success)) ++foo() diff --cc glcpp/tests/031-define-chain-func-to-func-compose.c.expected index 00000000000,00000000000..bed826e7831 new file mode 100644 --- /dev/null +++ b/glcpp/tests/031-define-chain-func-to-func-compose.c.expected @@@ -1,0 -1,0 +1,4 @@@ ++ ++ ++ ++success diff --cc glcpp/tests/032-define-func-self-recurse.c index 00000000000,00000000000..b3ac70f499c new file mode 100644 --- /dev/null +++ b/glcpp/tests/032-define-func-self-recurse.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(a) foo(2*(a)) ++foo(3) diff --cc glcpp/tests/032-define-func-self-recurse.c.expected index 00000000000,00000000000..983f9417401 new file mode 100644 --- /dev/null +++ b/glcpp/tests/032-define-func-self-recurse.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++foo(2*(3)) diff --cc glcpp/tests/033-define-func-self-compose.c index 00000000000,00000000000..f65e48286cf new file mode 100644 --- /dev/null +++ b/glcpp/tests/033-define-func-self-compose.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(a) foo(2*(a)) ++foo(foo(3)) diff --cc glcpp/tests/033-define-func-self-compose.c.expected index 00000000000,00000000000..08183623643 new file mode 100644 --- /dev/null +++ b/glcpp/tests/033-define-func-self-compose.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++foo(2*(foo(2*(3)))) diff --cc glcpp/tests/034-define-func-self-compose-non-func.c index 00000000000,00000000000..209a5f7e07c new file mode 100644 --- /dev/null +++ b/glcpp/tests/034-define-func-self-compose-non-func.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(bar) bar ++foo(foo) diff --cc glcpp/tests/034-define-func-self-compose-non-func.c.expected index 00000000000,00000000000..3f808fe665d new file mode 100644 --- /dev/null +++ b/glcpp/tests/034-define-func-self-compose-non-func.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++foo diff --cc glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c index 00000000000,00000000000..c307fbe830f new file mode 100644 --- /dev/null +++ b/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(bar) bar ++foo(1+foo) diff --cc glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected index 00000000000,00000000000..09dfdd64e9b new file mode 100644 --- /dev/null +++ b/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++1+foo diff --cc glcpp/tests/036-define-func-non-macro-multi-token-argument.c index 00000000000,00000000000..b21ff336738 new file mode 100644 --- /dev/null +++ b/glcpp/tests/036-define-func-non-macro-multi-token-argument.c @@@ -1,0 -1,0 +1,3 @@@ ++#define bar success ++#define foo(x) x ++foo(more bar) diff --cc glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected index 00000000000,00000000000..580ed9599c5 new file mode 100644 --- /dev/null +++ b/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++more success diff --cc glcpp/tests/037-finalize-unexpanded-macro.c index 00000000000,00000000000..b3a2f37f1b9 new file mode 100644 --- /dev/null +++ b/glcpp/tests/037-finalize-unexpanded-macro.c @@@ -1,0 -1,0 +1,3 @@@ ++#define expand(x) expand(x once) ++#define foo(x) x ++foo(expand(just)) diff --cc glcpp/tests/037-finalize-unexpanded-macro.c.expected index 00000000000,00000000000..e804d7e4f9f new file mode 100644 --- /dev/null +++ b/glcpp/tests/037-finalize-unexpanded-macro.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++expand(just once) diff --cc glcpp/tests/038-func-arg-with-commas.c index 00000000000,00000000000..1407c7d6e3c new file mode 100644 --- /dev/null +++ b/glcpp/tests/038-func-arg-with-commas.c @@@ -1,0 -1,0 +1,2 @@@ ++#define foo(x) success ++foo(argument (with,embedded , commas) -- tricky) diff --cc glcpp/tests/038-func-arg-with-commas.c.expected index 00000000000,00000000000..6544adb3a25 new file mode 100644 --- /dev/null +++ b/glcpp/tests/038-func-arg-with-commas.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++success diff --cc glcpp/tests/039-func-arg-obj-macro-with-comma.c index 00000000000,00000000000..0f7fe632b56 new file mode 100644 --- /dev/null +++ b/glcpp/tests/039-func-arg-obj-macro-with-comma.c @@@ -1,0 -1,0 +1,3 @@@ ++#define foo(a) (a) ++#define bar two,words ++foo(bar) diff --cc glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected index 00000000000,00000000000..8a15397a033 new file mode 100644 --- /dev/null +++ b/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++(two,words) diff --cc glcpp/tests/040-token-pasting.c index 00000000000,00000000000..caab3ba7368 new file mode 100644 --- /dev/null +++ b/glcpp/tests/040-token-pasting.c @@@ -1,0 -1,0 +1,2 @@@ ++#define paste(a,b) a ## b ++paste(one , token) diff --cc glcpp/tests/040-token-pasting.c.expected index 00000000000,00000000000..48e836ec3fa new file mode 100644 --- /dev/null +++ b/glcpp/tests/040-token-pasting.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++onetoken diff --cc glcpp/tests/041-if-0.c index 00000000000,00000000000..2cab677d3e8 new file mode 100644 --- /dev/null +++ b/glcpp/tests/041-if-0.c @@@ -1,0 -1,0 +1,5 @@@ ++success_1 ++#if 0 ++failure ++#endif ++success_2 diff --cc glcpp/tests/041-if-0.c.expected index 00000000000,00000000000..8b506b32d55 new file mode 100644 --- /dev/null +++ b/glcpp/tests/041-if-0.c.expected @@@ -1,0 -1,0 +1,5 @@@ ++success_1 ++ ++ ++ ++success_2 diff --cc glcpp/tests/042-if-1.c index 00000000000,00000000000..874a25cf41b new file mode 100644 --- /dev/null +++ b/glcpp/tests/042-if-1.c @@@ -1,0 -1,0 +1,5 @@@ ++success_1 ++#if 1 ++success_2 ++#endif ++success_3 diff --cc glcpp/tests/042-if-1.c.expected index 00000000000,00000000000..a6ae9465a97 new file mode 100644 --- /dev/null +++ b/glcpp/tests/042-if-1.c.expected @@@ -1,0 -1,0 +1,5 @@@ ++success_1 ++ ++success_2 ++ ++success_3 diff --cc glcpp/tests/043-if-0-else.c index 00000000000,00000000000..323351f9dbf new file mode 100644 --- /dev/null +++ b/glcpp/tests/043-if-0-else.c @@@ -1,0 -1,0 +1,7 @@@ ++success_1 ++#if 0 ++failure ++#else ++success_2 ++#endif ++success_3 diff --cc glcpp/tests/043-if-0-else.c.expected index 00000000000,00000000000..3d7e6be96c8 new file mode 100644 --- /dev/null +++ b/glcpp/tests/043-if-0-else.c.expected @@@ -1,0 -1,0 +1,7 @@@ ++success_1 ++ ++ ++ ++success_2 ++ ++success_3 diff --cc glcpp/tests/044-if-1-else.c index 00000000000,00000000000..28dfc25c6f0 new file mode 100644 --- /dev/null +++ b/glcpp/tests/044-if-1-else.c @@@ -1,0 -1,0 +1,7 @@@ ++success_1 ++#if 1 ++success_2 ++#else ++failure ++#endif ++success_3 diff --cc glcpp/tests/044-if-1-else.c.expected index 00000000000,00000000000..4a31e1cfa9e new file mode 100644 --- /dev/null +++ b/glcpp/tests/044-if-1-else.c.expected @@@ -1,0 -1,0 +1,7 @@@ ++success_1 ++ ++success_2 ++ ++ ++ ++success_3 diff --cc glcpp/tests/045-if-0-elif.c index 00000000000,00000000000..e50f686d461 new file mode 100644 --- /dev/null +++ b/glcpp/tests/045-if-0-elif.c @@@ -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 diff --cc glcpp/tests/045-if-0-elif.c.expected index 00000000000,00000000000..a9bb1588e4f new file mode 100644 --- /dev/null +++ b/glcpp/tests/045-if-0-elif.c.expected @@@ -1,0 -1,0 +1,11 @@@ ++success_1 ++ ++ ++ ++ ++ ++success_3 ++ ++ ++ ++success_4 diff --cc glcpp/tests/046-if-1-elsif.c index 00000000000,00000000000..130515a01ea new file mode 100644 --- /dev/null +++ b/glcpp/tests/046-if-1-elsif.c @@@ -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 diff --cc glcpp/tests/046-if-1-elsif.c.expected index 00000000000,00000000000..a4995713ca5 new file mode 100644 --- /dev/null +++ b/glcpp/tests/046-if-1-elsif.c.expected @@@ -1,0 -1,0 +1,11 @@@ ++success_1 ++ ++success_2 ++ ++ ++ ++ ++ ++ ++ ++success_3 diff --cc glcpp/tests/047-if-elif-else.c index 00000000000,00000000000..e8f0838a9ed new file mode 100644 --- /dev/null +++ b/glcpp/tests/047-if-elif-else.c @@@ -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 diff --cc glcpp/tests/047-if-elif-else.c.expected index 00000000000,00000000000..54d30861197 new file mode 100644 --- /dev/null +++ b/glcpp/tests/047-if-elif-else.c.expected @@@ -1,0 -1,0 +1,11 @@@ ++success_1 ++ ++ ++ ++ ++ ++ ++ ++success_2 ++ ++success_3 diff --cc glcpp/tests/048-if-nested.c index 00000000000,00000000000..fc4679c3be4 new file mode 100644 --- /dev/null +++ b/glcpp/tests/048-if-nested.c @@@ -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 diff --cc glcpp/tests/048-if-nested.c.expected index 00000000000,00000000000..8beb9c32c37 new file mode 100644 --- /dev/null +++ b/glcpp/tests/048-if-nested.c.expected @@@ -1,0 -1,0 +1,11 @@@ ++success_1 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++success_2 diff --cc glcpp/tests/049-if-expression-precedence.c index 00000000000,00000000000..833ea03882a new file mode 100644 --- /dev/null +++ b/glcpp/tests/049-if-expression-precedence.c @@@ -1,0 -1,0 +1,5 @@@ ++#if 1 + 2 * 3 + - (25 % 17 - + 1) ++failure with operator precedence ++#else ++success ++#endif diff --cc glcpp/tests/049-if-expression-precedence.c.expected index 00000000000,00000000000..729bdd15f80 new file mode 100644 --- /dev/null +++ b/glcpp/tests/049-if-expression-precedence.c.expected @@@ -1,0 -1,0 +1,5 @@@ ++ ++ ++ ++success ++ diff --cc glcpp/tests/050-if-defined.c index 00000000000,00000000000..34f0f95140e new file mode 100644 --- /dev/null +++ b/glcpp/tests/050-if-defined.c @@@ -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 diff --cc glcpp/tests/050-if-defined.c.expected index 00000000000,00000000000..737eb8d9403 new file mode 100644 --- /dev/null +++ b/glcpp/tests/050-if-defined.c.expected @@@ -1,0 -1,0 +1,17 @@@ ++ ++ ++ ++success_1 ++ ++ ++ ++success_2 ++ ++ ++ ++ ++ ++ ++ ++success_3 ++ diff --cc glcpp/tests/051-if-relational.c index 00000000000,00000000000..c3db488e0de new file mode 100644 --- /dev/null +++ b/glcpp/tests/051-if-relational.c @@@ -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 diff --cc glcpp/tests/051-if-relational.c.expected index 00000000000,00000000000..652fefdd43b new file mode 100644 --- /dev/null +++ b/glcpp/tests/051-if-relational.c.expected @@@ -1,0 -1,0 +1,35 @@@ ++ ++ ++ ++success_1 ++ ++ ++ ++success_2 ++ ++ ++ ++ ++ ++success_3 ++ ++ ++ ++ ++ ++success_3 ++ ++ ++ ++ ++ ++ ++ ++success_4 ++ ++ ++ ++success_5 ++ ++ ++ diff --cc glcpp/tests/052-if-bitwise.c index 00000000000,00000000000..2d8e45eb61e new file mode 100644 --- /dev/null +++ b/glcpp/tests/052-if-bitwise.c @@@ -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 diff --cc glcpp/tests/052-if-bitwise.c.expected index 00000000000,00000000000..44e52b206e5 new file mode 100644 --- /dev/null +++ b/glcpp/tests/052-if-bitwise.c.expected @@@ -1,0 -1,0 +1,20 @@@ ++ ++ ++ ++success_1 ++ ++ ++success_2 ++ ++ ++ ++ ++ ++ ++success_3 ++ ++ ++success_4 ++ ++ ++ diff --cc glcpp/tests/053-if-divide-and-shift.c index 00000000000,00000000000..d24c54a88d1 new file mode 100644 --- /dev/null +++ b/glcpp/tests/053-if-divide-and-shift.c @@@ -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 diff --cc glcpp/tests/053-if-divide-and-shift.c.expected index 00000000000,00000000000..7e78e0454e0 new file mode 100644 --- /dev/null +++ b/glcpp/tests/053-if-divide-and-shift.c.expected @@@ -1,0 -1,0 +1,15 @@@ ++ ++ ++ ++success_1 ++ ++ ++success_2 ++ ++ ++ ++ ++ ++ ++success_3 ++ diff --cc glcpp/tests/054-if-with-macros.c index 00000000000,00000000000..3da79a0d96e new file mode 100644 --- /dev/null +++ b/glcpp/tests/054-if-with-macros.c @@@ -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 diff --cc glcpp/tests/054-if-with-macros.c.expected index 00000000000,00000000000..70f737c90a9 new file mode 100644 --- /dev/null +++ b/glcpp/tests/054-if-with-macros.c.expected @@@ -1,0 -1,0 +1,34 @@@ ++ ++ ++ ++ ++ ++ ++ ++success_1 ++ ++ ++success_2 ++ ++ ++ ++ ++success_3 ++ ++ ++ ++ ++success_4 ++ ++ ++ ++ ++ ++ ++success_5 ++ ++ ++success_6 ++ ++ ++ diff --cc glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c index 00000000000,00000000000..00f2c2346d6 new file mode 100644 --- /dev/null +++ b/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c @@@ -1,0 -1,0 +1,3 @@@ ++#define failure() success ++#define foo failure ++foo() diff --cc glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected index 00000000000,00000000000..94c15f95059 new file mode 100644 --- /dev/null +++ b/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++success diff --cc glcpp/tests/056-macro-argument-with-comma.c index 00000000000,00000000000..58701d1f25b new file mode 100644 --- /dev/null +++ b/glcpp/tests/056-macro-argument-with-comma.c @@@ -1,0 -1,0 +1,4 @@@ ++#define bar with,embedded,commas ++#define function(x) success ++#define foo function ++foo(bar) diff --cc glcpp/tests/056-macro-argument-with-comma.c.expected index 00000000000,00000000000..bed826e7831 new file mode 100644 --- /dev/null +++ b/glcpp/tests/056-macro-argument-with-comma.c.expected @@@ -1,0 -1,0 +1,4 @@@ ++ ++ ++ ++success diff --cc glcpp/tests/057-empty-arguments.c index 00000000000,00000000000..6140232865d new file mode 100644 --- /dev/null +++ b/glcpp/tests/057-empty-arguments.c @@@ -1,0 -1,0 +1,6 @@@ ++#define zero() success ++zero() ++#define one(x) success ++one() ++#define two(x,y) success ++two(,) diff --cc glcpp/tests/057-empty-arguments.c.expected index 00000000000,00000000000..7d97e15e29d new file mode 100644 --- /dev/null +++ b/glcpp/tests/057-empty-arguments.c.expected @@@ -1,0 -1,0 +1,6 @@@ ++ ++success ++ ++success ++ ++success diff --cc glcpp/tests/058-token-pasting-empty-arguments.c index 00000000000,00000000000..8ac260c76b6 new file mode 100644 --- /dev/null +++ b/glcpp/tests/058-token-pasting-empty-arguments.c @@@ -1,0 -1,0 +1,5 @@@ ++#define paste(x,y) x ## y ++paste(a,b) ++paste(a,) ++paste(,b) ++paste(,) diff --cc glcpp/tests/058-token-pasting-empty-arguments.c.expected index 00000000000,00000000000..e0967a1b951 new file mode 100644 --- /dev/null +++ b/glcpp/tests/058-token-pasting-empty-arguments.c.expected @@@ -1,0 -1,0 +1,5 @@@ ++ ++ab ++a ++b ++ diff --cc glcpp/tests/059-token-pasting-integer.c index 00000000000,00000000000..37b895a4237 new file mode 100644 --- /dev/null +++ b/glcpp/tests/059-token-pasting-integer.c @@@ -1,0 -1,0 +1,4 @@@ ++#define paste(x,y) x ## y ++paste(1,2) ++paste(1,000) ++paste(identifier,2) diff --cc glcpp/tests/059-token-pasting-integer.c.expected index 00000000000,00000000000..f1288aa7cb7 new file mode 100644 --- /dev/null +++ b/glcpp/tests/059-token-pasting-integer.c.expected @@@ -1,0 -1,0 +1,4 @@@ ++ ++12 ++1000 ++identifier2 diff --cc glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c index 00000000000,00000000000..ed80ea879ce new file mode 100644 --- /dev/null +++ b/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c @@@ -1,0 -1,0 +1,3 @@@ ++#define double(a) a*2 ++#define foo double( ++foo 5) diff --cc glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected index 00000000000,00000000000..3e5501aa6e8 new file mode 100644 --- /dev/null +++ b/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected @@@ -1,0 -1,0 +1,3 @@@ ++ ++ ++5*2 diff --cc glcpp/tests/061-define-chain-obj-to-func-multi.c index 00000000000,00000000000..6dbfd1f62d1 new file mode 100644 --- /dev/null +++ b/glcpp/tests/061-define-chain-obj-to-func-multi.c @@@ -1,0 -1,0 +1,5 @@@ ++#define foo(x) success ++#define bar foo ++#define baz bar ++#define joe baz ++joe (failure) diff --cc glcpp/tests/061-define-chain-obj-to-func-multi.c.expected index 00000000000,00000000000..15eb64b97f1 new file mode 100644 --- /dev/null +++ b/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected @@@ -1,0 -1,0 +1,5 @@@ ++ ++ ++ ++ ++success diff --cc glcpp/tests/062-if-0-skips-garbage.c index 00000000000,00000000000..d9e439bb890 new file mode 100644 --- /dev/null +++ b/glcpp/tests/062-if-0-skips-garbage.c @@@ -1,0 -1,0 +1,5 @@@ ++#define foo(a,b) ++#if 0 ++foo(bar) ++foo( ++#endif diff --cc glcpp/tests/062-if-0-skips-garbage.c.expected index 00000000000,00000000000..3f2ff2d6cc8 new file mode 100644 --- /dev/null +++ b/glcpp/tests/062-if-0-skips-garbage.c.expected @@@ -1,0 -1,0 +1,5 @@@ ++ ++ ++ ++ ++ diff --cc glcpp/tests/063-comments.c index 00000000000,00000000000..e641d2f0f9e new file mode 100644 --- /dev/null +++ b/glcpp/tests/063-comments.c @@@ -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 */ ++/*/*/ diff --cc glcpp/tests/063-comments.c.expected index 00000000000,00000000000..4998d76cc22 new file mode 100644 --- /dev/null +++ b/glcpp/tests/063-comments.c.expected @@@ -1,0 -1,0 +1,13 @@@ ++ ++ ++ ++f = g /h; ++ l(); ++m = n +++ p; ++ ++more code here ++ ++are not treated like comments. ++ ++ diff --cc glcpp/tests/071-punctuator.c index 00000000000,00000000000..959d6825988 new file mode 100644 --- /dev/null +++ b/glcpp/tests/071-punctuator.c @@@ -1,0 -1,0 +1,1 @@@ ++a = b diff --cc glcpp/tests/071-punctuator.c.expected index 00000000000,00000000000..959d6825988 new file mode 100644 --- /dev/null +++ b/glcpp/tests/071-punctuator.c.expected @@@ -1,0 -1,0 +1,1 @@@ ++a = b diff --cc glcpp/tests/072-token-pasting-same-line.c index 00000000000,00000000000..e421e9d5e29 new file mode 100644 --- /dev/null +++ b/glcpp/tests/072-token-pasting-same-line.c @@@ -1,0 -1,0 +1,2 @@@ ++#define paste(x) success_ ## x ++paste(1) paste(2) paste(3) diff --cc glcpp/tests/072-token-pasting-same-line.c.expected index 00000000000,00000000000..7b80af7e465 new file mode 100644 --- /dev/null +++ b/glcpp/tests/072-token-pasting-same-line.c.expected @@@ -1,0 -1,0 +1,2 @@@ ++ ++success_1 success_2 success_3 diff --cc glcpp/tests/099-c99-example.c index 00000000000,00000000000..d1976b1f265 new file mode 100644 --- /dev/null +++ b/glcpp/tests/099-c99-example.c @@@ -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(,)}; diff --cc glcpp/tests/099-c99-example.c.expected index 00000000000,00000000000..352bbff48f5 new file mode 100644 --- /dev/null +++ b/glcpp/tests/099-c99-example.c.expected @@@ -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, }; diff --cc glcpp/tests/glcpp-test index 00000000000,00000000000..396f6e175e8 new file mode 100755 --- /dev/null +++ b/glcpp/tests/glcpp-test @@@ -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 00000000000,00000000000..656ac2d6cb5 new file mode 100644 --- /dev/null +++ b/glcpp/xtalloc.c @@@ -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 ++ ++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; ++}