tests: restructure for clarity

* tests/calc.at (AT_CALC_MAIN, AT_CALC_LEX): Rewrite on top of
AT_LANG_DISPATCH.
This commit is contained in:
Akim Demaille
2019-06-23 13:21:02 +02:00
parent 0984f70e08
commit 63f4dca78f

View File

@@ -19,44 +19,13 @@
## Compile the grammar described in the documentation. ## ## Compile the grammar described in the documentation. ##
## ---------------------------------------------------- ## ## ---------------------------------------------------- ##
# -------------- #
# AT_CALC_MAIN. #
# -------------- #
# ------------------------- # m4_pushdef([AT_CALC_MAIN], [AT_LANG_DISPATCH([$0], $@)])
# Helping Autotest macros. #
# ------------------------- #
m4_define([AT_CALC_MAIN(c)],
# _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],
[[#include <assert.h> [[#include <assert.h>
#include <unistd.h> #include <unistd.h>
@@ -113,9 +82,127 @@ main (int argc, const char **argv)
assert (global_count == count); (void) count; assert (global_count == count); (void) count;
return status; 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 <ctype.h>
]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.range.primitives;
import std.stdio; import std.stdio;
@@ -216,99 +303,32 @@ class CalcLexer(R) : Lexer
return c; return c;
} }
} }
]])],
[m4_pushdef([AT_CALC_LEX],
[[#include <ctype.h>
]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], AT_DATA_GRAMMAR([calc.y],
[[/* Infix notation calculator--calc */ [[/* Infix notation calculator--calc */
@@ -381,15 +401,15 @@ void location_print (FILE *o, Span s);
%code %code
{ {
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#define USE(Var) #define USE(Var)
FILE *input; FILE *input;
static int power (int base, int exponent); static int power (int base, int exponent);
]AT_YYERROR_DECLARE[ ]AT_YYERROR_DECLARE[
]AT_YYLEX_DECLARE_EXTERN[ ]AT_YYLEX_DECLARE_EXTERN[
} }
]])[ ]])[
@@ -484,20 +504,18 @@ location_print (FILE *o, Span s)
]])])[ ]])])[
]AT_YYERROR_DEFINE[ ]AT_YYERROR_DEFINE[
]AT_DEFINES_IF([], ]AT_DEFINES_IF([],
[AT_CALC_LEX [AT_CALC_YYLEX
AT_CALC_MAIN])]) AT_CALC_MAIN])])
AT_DEFINES_IF([AT_DATA_SOURCE([[calc-lex.]AT_LANG_EXT], AT_DEFINES_IF([AT_DATA_SOURCE([[calc-lex.]AT_LANG_EXT],
[[#include "calc.]AT_LANG_HDR[" [[#include "calc.]AT_LANG_HDR["
]AT_CALC_LEX]) ]AT_CALC_YYLEX])
AT_DATA_SOURCE([[calc-main.]AT_LANG_EXT], AT_DATA_SOURCE([[calc-main.]AT_LANG_EXT],
[[#include "calc.]AT_LANG_HDR[" [[#include "calc.]AT_LANG_HDR["
]AT_CALC_MAIN]) ]AT_CALC_MAIN])
]) ])
m4_popdef([AT_CALC_MAIN])
m4_popdef([AT_CALC_LEX])
])# _AT_DATA_CALC_Y ])# _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 %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}]) #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])