Files
bison/tests/scanner.at
Adela Vais 32bb53870b d: remove unnecessary methods from the Lexer interface
The complete symbol approach in yylex removes the need for the methods
semanticVal, startPos and endPos, which were used when the values were
reported separately.

* data/skeletons/lalr1.d: Here.
* doc/bison.texi: Remove sections about the three methods.
* examples/d/calc/calc.y, examples/d/simple/calc.y: Remove the unused methods.
* tests/calc.at, tests/d.at, tests/scanner.at: Test it.
2020-12-21 15:53:32 +01:00

340 lines
7.7 KiB
Plaintext

# Interface with the scanner. -*- Autotest -*-
# Copyright (C) 2019-2020 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[
Value semanticVal_;
Symbol yylex ()
{
import std.uni : isNumber;
// Handle EOF.
if (input.empty)
return Symbol(TokenKind.END);
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 Symbol(TokenKind.NUM, semanticVal_.val);
case '+': return Symbol(TokenKind.PLUS);
case '-': return Symbol(TokenKind.MINUS);
case '*': return Symbol(TokenKind.STAR);
case '/': return Symbol(TokenKind.SLASH);
case '(': return Symbol(TokenKind.LPAR);
case ')': return Symbol(TokenKind.RPAR);
default: assert(0);
}
}
}
]])
m4_pushdef([AT_MAIN_DEFINE(d)],
[[int main ()
{
auto l = yyLexer ();
auto p = new YYParser (l);
return !p.parse ();
}]])
m4_pushdef([AT_MAIN_DEFINE(java)],
[[class input
{
public static void main (String[] args) throws IOException
{]AT_LEXPARAM_IF([[
]AT_PARSER_CLASS[ p = new ]AT_PARSER_CLASS[ (System.in);]], [[
]AT_API_prefix[Lexer l = new ]AT_API_prefix[Lexer (System.in);
]AT_PARSER_CLASS[ p = new ]AT_PARSER_CLASS[ (l);]])AT_DEBUG_IF([[
//p.setDebugLevel (1);]])[
boolean success = p.parse ();
if (!success)
System.exit (1);
}
}]])
m4_define([AT_RAW_YYLEX(java)],
[[class CalcLexer implements Calc.Lexer {
StreamTokenizer st;
public CalcLexer(InputStream is) {
st = new StreamTokenizer(new StringReader("0-(1+2)*3/9"));
st.resetSyntax();
st.eolIsSignificant(true);
st.whitespaceChars('\t', '\t');
st.whitespaceChars(' ', ' ');
st.wordChars('0', '9');
}
public void yyerror(String s) {
System.err.println(s);
}
Integer yylval;
public Object getLVal() {
return yylval;
}
public int yylex() throws IOException {
int ttype = st.nextToken();
switch (ttype)
{
case StreamTokenizer.TT_EOF:
return EOF;
case StreamTokenizer.TT_EOL:
return (int) '\n';
case StreamTokenizer.TT_WORD:
yylval = Integer.parseInt(st.sval);
return NUM;
case '+':
return PLUS;
case '-':
return MINUS;
case '*':
return STAR;
case '/':
return SLASH;
case '(':
return LPAR;
case ')':
return RPAR;
default:
throw new AssertionError("invalid character: " + ttype);
}
}
}
]])
## ------------------- ##
## Raw token numbers. ##
## ------------------- ##
m4_pushdef([AT_TEST],
[
AT_SETUP([Token numbers: $1])
AT_BISON_OPTION_PUSHDEFS([%debug ]m4_bmatch([$1], [java], [[%define api.prefix {Calc} %define api.parser.class {Calc}]])[ $1])
AT_DATA_GRAMMAR([[input.y]],
[[$1
%debug
]AT_LANG_MATCH([[c\|c++]], [[
%code
{
#include <stdio.h>
]AT_YYERROR_DECLARE[
]AT_YYLEX_DECLARE[
}]],
[java], [[
%define api.prefix {Calc}
%define api.parser.class {Calc}
%code imports {
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.Reader;
import java.io.StreamTokenizer;
}
]])[
]AT_LANG_MATCH([c\|c++\|d],
[AT_VARIANT_IF([[
%token <int> NUM "number"
%nterm <int> exp
]], [[
%union {
int val;
}
%token <val> NUM "number"
%nterm <val> exp
]])],
[java],
[[%token <Integer> NUM "number"
%type <Integer> exp
]])[
%token
PLUS "+"
MINUS "-"
STAR "*"
SLASH "/"
LPAR "("
RPAR ")"
END 0
%left "+" "-"
%left "*" "/"
%%
input
: exp { ]AT_JAVA_IF([[System.out.println ($][1)]], [[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_LANG_MATCH([c\|c++\|d],
[AT_YYERROR_DEFINE])[
]AT_RAW_YYLEX[
]AT_MAIN_DEFINE[
]])
AT_FULL_COMPILE([input])
# When api.token.raw, the yytranslate table should not be included.
#
# 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_).
# lalr1.java uses 'byte[] translate_table_ =' (and yytranslate_).
AT_CHECK([[$EGREP -c 'yytranslate\[\]|translate_table\[\]|translate_table =|translate_table_ =' input.]AT_LANG_EXT],
[ignore],
[AT_D_IF([AT_TOKEN_RAW_IF([0], [0])],
[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], [glr2.cc], [lalr1.java], [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(java)])
m4_popdef([AT_MAIN_DEFINE(d)])
m4_popdef([AT_TEST])