mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 12:23:04 +00:00
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:
303
tests/calc.at
303
tests/calc.at
@@ -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])
|
||||||
|
|||||||
Reference in New Issue
Block a user