| /* Simple parser and scanner in Java. -*- Java -*- |
| |
| Copyright (C) 2018-2022, 2025-2026 Free Software Foundation, Inc. |
| |
| This file is part of Bison, the GNU Compiler Compiler. |
| |
| 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/>. */ |
| |
| %language "Java" |
| |
| %define api.parser.class {Calc} |
| %define api.parser.public |
| |
| %define parse.error verbose |
| |
| %code imports { |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.Reader; |
| import java.io.StreamTokenizer; |
| } |
| |
| %code { |
| public static void main(String[] args) throws IOException { |
| CalcLexer l = new CalcLexer(System.in); |
| Calc p = new Calc(l); |
| if (!p.parse()) |
| System.exit(1); |
| } |
| } |
| |
| /* Bison Declarations */ |
| %token <Integer> NUM "number" |
| %type <Integer> exp |
| |
| %nonassoc '=' /* comparison */ |
| %left '-' '+' |
| %left '*' '/' |
| %precedence NEG /* negation--unary minus */ |
| %right '^' /* exponentiation */ |
| |
| /* Grammar follows */ |
| %% |
| input: |
| line |
| | input line |
| ; |
| |
| line: |
| '\n' |
| | exp '\n' { System.out.println($exp); } |
| | error '\n' |
| ; |
| |
| exp: |
| NUM { $$ = $1; } |
| | exp '=' exp |
| { |
| if ($1.intValue() != $3.intValue()) |
| yyerror("calc: error: " + $1 + " != " + $3); |
| } |
| | exp '+' exp { $$ = $1 + $3; } |
| | exp '-' exp { $$ = $1 - $3; } |
| | exp '*' exp { $$ = $1 * $3; } |
| | exp '/' exp { $$ = $1 / $3; } |
| | '-' exp %prec NEG { $$ = -$2; } |
| | exp '^' exp { $$ = (int) Math.pow($1, $3); } |
| | '(' exp ')' { $$ = $2; } |
| | '(' error ')' { $$ = 1111; } |
| | '!' { $$ = 0; return YYERROR; } |
| | '-' error { $$ = 0; return YYERROR; } |
| ; |
| |
| |
| %% |
| class CalcLexer implements Calc.Lexer { |
| |
| StreamTokenizer st; |
| |
| public CalcLexer(InputStream is) { |
| st = new StreamTokenizer(new InputStreamReader(is)); |
| 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 YYEOF; |
| case StreamTokenizer.TT_EOL: |
| return (int) '\n'; |
| case StreamTokenizer.TT_WORD: |
| yylval = Integer.parseInt(st.sval); |
| return NUM; |
| default: |
| return ttype; |
| } |
| } |
| } |