# Interface with the scanner. -*- Autotest -*- # Copyright (C) 2019-2022 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 . 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 /* 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 /* 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[ 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': return Symbol(TokenKind.NUM, c - '0'); 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 ]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 NUM "number" %nterm exp ]], [[ %union { int val; } %token NUM "number" %nterm exp ]])], [java], [[%token NUM "number" %type 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 ]) AT_FOR_EACH_SKEL( [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])