# 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 . 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[ 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 ]AT_YYERROR_DECLARE[ ]AT_YYLEX_DECLARE[ }]])[ ]AT_VARIANT_IF([[ %token NUM "number" %nterm exp ]], [[ %union { int val; } %token NUM "number" %nterm 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])