| # 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]) |