blob: c03dbbbdf8bc614c69129b6264a88250e1e886e5 [file] [log] [blame]
# Interface with the scanner. -*- Autotest -*-
# Copyright (C) 2019 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
AT_BANNER([[Interface with the scanner.]])
# -------------- #
# AT_RAW_YYLEX. #
# -------------- #
m4_pushdef([AT_RAW_YYLEX], [AT_LANG_DISPATCH([$0], $@)])
m4_define([AT_RAW_YYLEX(c)],
[#include <stdlib.h> /* abort */
AT_YYLEX_PROTOTYPE[
{
static const char* input = "0-(1+2)*3/9";
int c = *input++;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
]AT_VAL[.val = c - '0';
return NUM;
case '+': return PLUS;
case '-': return MINUS;
case '*': return STAR;
case '/': return SLASH;
case '(': return LPAR;
case ')': return RPAR;
case 0: return 0;
}
abort ();
}
]])
m4_define([AT_RAW_YYLEX(c++)],
[#include <stdlib.h> /* abort */
AT_YYLEX_PROTOTYPE[
{
static const char* input = "0-(1+2)*3/9";
int c = *input++;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':]AT_TOKEN_CTOR_IF([[
return yy::parser::make_NUM (c - '0');]], [[
]AT_VAL[.val = c - '0';
return yy::parser::token::NUM;]])[
case '+': return yy::parser::]AT_TOKEN_CTOR_IF([make_PLUS ()], [token::PLUS])[;
case '-': return yy::parser::]AT_TOKEN_CTOR_IF([make_MINUS ()], [token::MINUS])[;
case '*': return yy::parser::]AT_TOKEN_CTOR_IF([make_STAR ()], [token::STAR])[;
case '/': return yy::parser::]AT_TOKEN_CTOR_IF([make_SLASH ()], [token::SLASH])[;
case '(': return yy::parser::]AT_TOKEN_CTOR_IF([make_LPAR ()], [token::LPAR])[;
case ')': return yy::parser::]AT_TOKEN_CTOR_IF([make_RPAR ()], [token::RPAR])[;
case 0: return yy::parser::]AT_TOKEN_CTOR_IF([make_END ()], [token::END])[;
}
abort ();
}
]])
m4_define([AT_RAW_YYLEX(d)],
[[import std.range.primitives;
import std.stdio;
auto yyLexer(R)(R range)
if (isInputRange!R && is (ElementType!R : dchar))
{
return new YYLexer!R(range);
}
auto yyLexer ()
{
return yyLexer("0-(1+2)*3/9");
}
class YYLexer(R) : Lexer
if (isInputRange!R && is (ElementType!R : dchar))
{
R input;
this(R r) {
input = r;
}
]AT_YYERROR_DEFINE[
YYSemanticType semanticVal_;
public final @property YYSemanticType semanticVal ()
{
return semanticVal_;
}
int yylex ()
{
import std.uni : isNumber;
// Handle EOF.
if (input.empty)
return YYTokenType.EOF;
auto c = input.front;
input.popFront;
// Numbers.
switch (c)
{
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
semanticVal_.val = c - '0';
return YYTokenType.NUM;
case '+': return YYTokenType.PLUS;
case '-': return YYTokenType.MINUS;
case '*': return YYTokenType.STAR;
case '/': return YYTokenType.SLASH;
case '(': return YYTokenType.LPAR;
case ')': return YYTokenType.RPAR;
default: assert(0);
}
}
}
]])
m4_pushdef([AT_MAIN_DEFINE(d)],
[[int main ()
{
auto l = yyLexer ();
auto p = new YYParser (l);
return !p.parse ();
}]])
## ------------------- ##
## Raw token numbers. ##
## ------------------- ##
m4_pushdef([AT_TEST],
[
AT_SETUP([Token numbers: $1])
AT_BISON_OPTION_PUSHDEFS([%debug $1])
AT_DATA_GRAMMAR([[input.y]],
[[$1
%debug
]AT_D_IF([], [[
%code
{
#include <stdio.h>
]AT_YYERROR_DECLARE[
]AT_YYLEX_DECLARE[
}]])[
]AT_VARIANT_IF([[
%token <int> NUM "number"
%nterm <int> exp
]], [[
%union {
int val;
}
%token <val> NUM "number"
%nterm <val> exp
]])[
%token
PLUS "+"
MINUS "-"
STAR "*"
SLASH "/"
LPAR "("
RPAR ")"
END 0
%left "+" "-"
%left "*" "/"
%%
input
: exp { printf ("%d\n", $][1); }
;
exp
: exp "+" exp { $][$][ = $][1 + $][3; }
| exp "-" exp { $][$][ = $][1 - $][3; }
| exp "*" exp { $][$][ = $][1 * $][3; }
| exp "/" exp { $][$][ = $][1 / $][3; }
| "(" exp ")" { $][$][ = $][2; }
| "number" { $][$][ = $][1; }
;
%%
]AT_YYERROR_DEFINE[
]AT_RAW_YYLEX[
]AT_MAIN_DEFINE[
]])
AT_FULL_COMPILE([input])
# yacc.c, glr.c and glr.cc use 'yytranslate' (and YYTRANSLATE).
# lalr1.cc uses 'translate_table' (and yytranslate_).
# lalr1.d uses 'byte[] translate_table =' (and yytranslate_).
AT_CHECK([[$EGREP -c 'yytranslate\[\]|translate_table\[\]|translate_table =' input.]AT_LANG_EXT],
[ignore],
[AT_TOKEN_RAW_IF([0], [1])[
]])
AT_PARSER_CHECK([input], 0,
[[-1
]])
AT_BISON_OPTION_POPDEFS
AT_CLEANUP
])
m4_foreach([b4_skel], [[yacc.c], [glr.c], [lalr1.cc], [glr.cc], [lalr1.d]],
[AT_TEST([%skeleton "]b4_skel["])
AT_TEST([%skeleton "]b4_skel[" %define api.token.raw])])
AT_TEST([%skeleton "lalr1.cc" %define api.token.raw %define api.value.type variant %define api.token.constructor])])
m4_popdef([AT_MAIN_DEFINE(d)])
m4_popdef([AT_TEST])