| # Interface with the scanner. -*- Autotest -*- |
| |
| # Copyright (C) 2019-2022, 2025 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 <https://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[ |
| |
| 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 <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 |
| ]) |
| |
| 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]) |