From 63f4dca78fce0e3a4c211911318b2d63c668d06a Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Sun, 23 Jun 2019 13:21:02 +0200 Subject: [PATCH] tests: restructure for clarity * tests/calc.at (AT_CALC_MAIN, AT_CALC_LEX): Rewrite on top of AT_LANG_DISPATCH. --- tests/calc.at | 303 +++++++++++++++++++++++++++----------------------- 1 file changed, 162 insertions(+), 141 deletions(-) diff --git a/tests/calc.at b/tests/calc.at index 77537610..79c40ac6 100644 --- a/tests/calc.at +++ b/tests/calc.at @@ -19,44 +19,13 @@ ## Compile the grammar described in the documentation. ## ## ---------------------------------------------------- ## +# -------------- # +# AT_CALC_MAIN. # +# -------------- # -# ------------------------- # -# Helping Autotest macros. # -# ------------------------- # +m4_pushdef([AT_CALC_MAIN], [AT_LANG_DISPATCH([$0], $@)]) - -# _AT_DATA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES]) -# ----------------------------------------------- -# Produce 'calc.y' and, if %defines was specified, 'calc-lex.c' or -# 'calc-lex.cc'. -# -# Don't call this macro directly, because it contains some occurrences -# of '$1' etc. which will be interpreted by m4. So you should call it -# with $1, $2, and $3 as arguments, which is what AT_DATA_CALC_Y does. -# -# When %defines is not passed, generate a single self-contained file. -# Otherwise, generate three: calc.y with the parser, calc-lex.c with -# the scanner, and calc-main.c with "main()". This is in order to -# stress the use of the generated parser header. To avoid code -# duplication, AT_CALC_LEX and AT_CALC_MAIN contain the body of these -# two later files. -m4_define([_AT_DATA_CALC_Y], -[m4_if([$1$2$3], $[1]$[2]$[3], [], - [m4_fatal([$0: Invalid arguments: $@])])dnl - -AT_D_IF([m4_pushdef([AT_CALC_MAIN], -[[int main (string[] args) -{ - semantic_value result = 0; - int count = 0; - - File input = args.length == 2 ? File (args[1], "r") : stdin; - auto l = calcLexer (input); - auto p = new YYParser (l); - return !p.parse (); -} -]])], -[m4_pushdef([AT_CALC_MAIN], +m4_define([AT_CALC_MAIN(c)], [[#include #include @@ -113,9 +82,127 @@ main (int argc, const char **argv) assert (global_count == count); (void) count; return status; } -]])]) +]]) -AT_D_IF([m4_pushdef([AT_CALC_LEX], +m4_copy([AT_CALC_MAIN(c)], [AT_CALC_MAIN(c++)]) + +m4_define([AT_CALC_MAIN(d)], +[[int main (string[] args) +{ + semantic_value result = 0; + int count = 0; + + File input = args.length == 2 ? File (args[1], "r") : stdin; + auto l = calcLexer (input); + auto p = new YYParser (l); + return !p.parse (); +} +]]) + + + +# --------------- # +# AT_CALC_YYLEX. # +# --------------- # + +m4_pushdef([AT_CALC_YYLEX], [AT_LANG_DISPATCH([$0], $@)]) + + +m4_define([AT_CALC_YYLEX(c)], +[[#include + +]AT_YYLEX_DECLARE_EXTERN[ + +]AT_LOCATION_IF([ +static AT_YYLTYPE last_yylloc; +])[ +static int +get_char (]AT_YYLEX_FORMALS[) +{ + int res = getc (input); + ]AT_USE_LEX_ARGS[; +]AT_LOCATION_IF([ + last_yylloc = AT_LOC; + if (res == '\n') + { + AT_LOC_LAST_LINE++; + AT_LOC_LAST_COLUMN = 1; + } + else + AT_LOC_LAST_COLUMN++; +])[ + return res; +} + +static void +unget_char (]AT_YYLEX_PRE_FORMALS[ int c) +{ + ]AT_USE_LEX_ARGS[; +]AT_LOCATION_IF([ + /* Wrong when C == '\n'. */ + AT_LOC = last_yylloc; +])[ + ungetc (c, input); +} + +static int +read_integer (]AT_YYLEX_FORMALS[) +{ + int c = get_char (]AT_YYLEX_ARGS[); + int res = 0; + + ]AT_USE_LEX_ARGS[; + while (isdigit (c)) + { + res = 10 * res + (c - '0'); + c = get_char (]AT_YYLEX_ARGS[); + } + + unget_char (]AT_YYLEX_PRE_ARGS[ c); + + return res; +} + + +/*---------------------------------------------------------------. +| Lexical analyzer returns an integer on the stack and the token | +| NUM, or the ASCII character read if not a number. Skips all | +| blanks and tabs, returns 0 for EOF. | +`---------------------------------------------------------------*/ + +]AT_YYLEX_PROTOTYPE[ +{ + int c; + /* Skip white spaces. */ + do + { +]AT_LOCATION_IF( +[ AT_LOC_FIRST_COLUMN = AT_LOC_LAST_COLUMN; + AT_LOC_FIRST_LINE = AT_LOC_LAST_LINE; +])[ + } + while ((c = get_char (]AT_YYLEX_ARGS[)) == ' ' || c == '\t'); + + /* Process numbers. */ + if (isdigit (c)) + { + unget_char (]AT_YYLEX_PRE_ARGS[ c); + ]AT_VAL[.ival = read_integer (]AT_YYLEX_ARGS[); + return ]AT_TOKEN_PREFIX[NUM; + } + + /* Return end-of-file. */ + if (c == EOF) + return ]AT_TOKEN_PREFIX[CALC_EOF; + + /* Return single chars. */ + return c; +} +]]) + +m4_copy([AT_CALC_YYLEX(c)], [AT_CALC_YYLEX(c++)]) + +m4_define([AT_CALC_YYLEX(d)], [[import std.range.primitives; import std.stdio; @@ -216,99 +303,32 @@ class CalcLexer(R) : Lexer return c; } } -]])], -[m4_pushdef([AT_CALC_LEX], -[[#include - -]AT_YYLEX_DECLARE_EXTERN[ - -]AT_LOCATION_IF([ -static AT_YYLTYPE last_yylloc; -])[ -static int -get_char (]AT_YYLEX_FORMALS[) -{ - int res = getc (input); - ]AT_USE_LEX_ARGS[; -]AT_LOCATION_IF([ - last_yylloc = AT_LOC; - if (res == '\n') - { - AT_LOC_LAST_LINE++; - AT_LOC_LAST_COLUMN = 1; - } - else - AT_LOC_LAST_COLUMN++; -])[ - return res; -} - -static void -unget_char (]AT_YYLEX_PRE_FORMALS[ int c) -{ - ]AT_USE_LEX_ARGS[; -]AT_LOCATION_IF([ - /* Wrong when C == '\n'. */ - AT_LOC = last_yylloc; -])[ - ungetc (c, input); -} - -static int -read_integer (]AT_YYLEX_FORMALS[) -{ - int c = get_char (]AT_YYLEX_ARGS[); - int res = 0; - - ]AT_USE_LEX_ARGS[; - while (isdigit (c)) - { - res = 10 * res + (c - '0'); - c = get_char (]AT_YYLEX_ARGS[); - } - - unget_char (]AT_YYLEX_PRE_ARGS[ c); - - return res; -} - - -/*---------------------------------------------------------------. -| Lexical analyzer returns an integer on the stack and the token | -| NUM, or the ASCII character read if not a number. Skips all | -| blanks and tabs, returns 0 for EOF. | -`---------------------------------------------------------------*/ - -]AT_YYLEX_PROTOTYPE[ -{ - int c; - /* Skip white spaces. */ - do - { -]AT_LOCATION_IF( -[ AT_LOC_FIRST_COLUMN = AT_LOC_LAST_COLUMN; - AT_LOC_FIRST_LINE = AT_LOC_LAST_LINE; -])[ - } - while ((c = get_char (]AT_YYLEX_ARGS[)) == ' ' || c == '\t'); - - /* Process numbers. */ - if (isdigit (c)) - { - unget_char (]AT_YYLEX_PRE_ARGS[ c); - ]AT_VAL[.ival = read_integer (]AT_YYLEX_ARGS[); - return ]AT_TOKEN_PREFIX[NUM; - } - - /* Return end-of-file. */ - if (c == EOF) - return ]AT_TOKEN_PREFIX[CALC_EOF; - - /* Return single chars. */ - return c; -} ]]) -]) + + +# -------------- # +# AT_DATA_CALC. # +# -------------- # + + +# _AT_DATA_CALC_Y($1, $2, $3, [BISON-DIRECTIVES]) +# ----------------------------------------------- +# Produce 'calc.y' and, if %defines was specified, 'calc-lex.c' or +# 'calc-lex.cc'. +# +# Don't call this macro directly, because it contains some occurrences +# of '$1' etc. which will be interpreted by m4. So you should call it +# with $1, $2, and $3 as arguments, which is what AT_DATA_CALC_Y does. +# +# When %defines is not passed, generate a single self-contained file. +# Otherwise, generate three: calc.y with the parser, calc-lex.c with +# the scanner, and calc-main.c with "main()". This is in order to +# stress the use of the generated parser header. To avoid code +# duplication, AT_CALC_YYLEX and AT_CALC_MAIN contain the body of these +# two later files. +m4_define([_AT_DATA_CALC_Y], +[m4_if([$1$2$3], $[1]$[2]$[3], [], + [m4_fatal([$0: Invalid arguments: $@])])dnl AT_DATA_GRAMMAR([calc.y], [[/* Infix notation calculator--calc */ @@ -381,15 +401,15 @@ void location_print (FILE *o, Span s); %code { -#include -#include -#define USE(Var) + #include + #include + #define USE(Var) -FILE *input; -static int power (int base, int exponent); + FILE *input; + static int power (int base, int exponent); -]AT_YYERROR_DECLARE[ -]AT_YYLEX_DECLARE_EXTERN[ + ]AT_YYERROR_DECLARE[ + ]AT_YYLEX_DECLARE_EXTERN[ } ]])[ @@ -484,20 +504,18 @@ location_print (FILE *o, Span s) ]])])[ ]AT_YYERROR_DEFINE[ ]AT_DEFINES_IF([], -[AT_CALC_LEX +[AT_CALC_YYLEX AT_CALC_MAIN])]) AT_DEFINES_IF([AT_DATA_SOURCE([[calc-lex.]AT_LANG_EXT], [[#include "calc.]AT_LANG_HDR[" -]AT_CALC_LEX]) +]AT_CALC_YYLEX]) AT_DATA_SOURCE([[calc-main.]AT_LANG_EXT], [[#include "calc.]AT_LANG_HDR[" ]AT_CALC_MAIN]) ]) -m4_popdef([AT_CALC_MAIN]) -m4_popdef([AT_CALC_LEX]) ])# _AT_DATA_CALC_Y @@ -902,3 +920,6 @@ AT_CHECK_CALC_LALR1_D([%define parse.error verbose %debug %verbose]) #AT_CHECK_CALC_LALR1_D([%locations %define parse.error verbose %debug %verbose %parse-param {semantic_value *result} %parse-param {int *count}]) #AT_CHECK_CALC_LALR1_D([%locations %define parse.error verbose %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result} %parse-param {int *count}]) + +m4_popdef([AT_CALC_MAIN]) +m4_popdef([AT_CALC_YYLEX])