1 /* Parser and scanner for calc in Java. -*- Java -*-
3 Copyright (C) 2018-2021 Free Software Foundation, Inc.
5 This file is part of Bison, the GNU Compiler Compiler.
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>. */
22 %define api.parser.class
{Calc
}
23 %define api.parser.public
24 %define api.push
-pull push
26 %define parse.
error custom
32 import java.io.BufferedReader
;
33 import java.io.IOException
;
34 import java.io.InputStream
;
35 import java.io.InputStreamReader
;
36 import java.io.Reader
;
37 import java.io.StreamTokenizer
;
38 import java.nio.CharBuffer
;
42 public
static void main
(String
[] args
) throws IOException
{
43 CalcLexer scanner
= new CalcLexer
(System.in
);
44 Calc parser
= new Calc
(scanner
);
45 for
(String arg
: args
)
47 parser.setDebugLevel
(1);
50 int token
= scanner.getToken
();
51 Object lval
= scanner.getValue
();
52 Calc.Location yyloc
= scanner.getLocation
();
53 status
= parser.push_parse
(token
, lval
, yyloc
);
54 } while
(status
== Calc.YYPUSH_MORE
);
55 if
(status
!= Calc.
YYACCEPT)
59 static String i18n
(String s
) {
64 /* Bison Declarations */
80 %nonassoc
"=" /* comparison */
83 %precedence NEG
/* negation--unary minus */
84 %right
"^" /* exponentiation */
95 | exp EOL
{ System.out.println
($exp); }
103 if
($1.intValue
() != $3.intValue
())
104 yyerror(@$
, "calc: error: " + $1 + " != " + $3);
106 | exp
"+" exp
{ $$
= $1 + $3; }
107 | exp
"-" exp
{ $$
= $1 - $3; }
108 | exp
"*" exp
{ $$
= $1 * $3; }
109 | exp
"/" exp
{ $$
= $1 / $3; }
110 |
"-" exp %prec NEG
{ $$
= -$2; }
111 | exp
"^" exp
{ $$
= (int) Math.pow
($1, $3); }
112 |
"(" exp
")" { $$
= $2; }
113 |
"(" error ")" { $$
= 1111; }
114 |
"!" { $$
= 0; return
YYERROR; }
115 |
"-" error { $$
= 0; return
YYERROR; }
119 class CalcLexer implements Calc.Lexer
{
122 PositionReader reader
;
124 public CalcLexer
(InputStream is
) {
125 reader
= new PositionReader
(new InputStreamReader
(is
));
126 st
= new StreamTokenizer
(reader
);
128 st.eolIsSignificant
(true
);
129 st.wordChars
('0', '9');
132 Position start
= new Position
(1, 0);
133 Position end
= new Position
(1, 0);
136 * The location of the last token read.
137 * Implemented with getStartPos and getEndPos in pull parsers.
139 public Calc.Location getLocation
() {
140 return new Calc.Location
(new Position
(start
), new Position
(end
));
144 * Build and emit a syntax error message.
146 public
void reportSyntaxError
(Calc.Context ctx
) {
147 System.err.print
(ctx.getLocation
() + ": syntax error");
149 final
int TOKENMAX
= 10;
150 Calc.SymbolKind
[] arg
= new Calc.SymbolKind
[TOKENMAX
];
151 int n
= ctx.getExpectedTokens
(arg
, TOKENMAX
);
152 for
(int i
= 0; i
< n
; ++i
)
153 System.err.print
((i
== 0 ?
": expected " : " or ")
157 Calc.SymbolKind lookahead
= ctx.getToken
();
158 if
(lookahead
!= null
)
159 System.err.print
(" before " + lookahead.getName
());
161 System.err.println
("");
165 * Emit an error referring to the given location in a user-defined way.
167 * @@param loc The location of the element to which the
168 * error message is related.
169 * @@param msg The string for the error message.
171 public
void yyerror(Calc.Location loc
, String msg
) {
173 System.err.println
(msg
);
175 System.err.println
(loc
+ ": " + msg
);
181 * The value of the last token read. Called getLVal in pull parsers.
183 public Object getValue
() {
188 * Fetch the next token. Called yylex in pull parsers.
190 public
int getToken
() throws IOException
{
191 start.set
(reader.getPosition
());
192 int ttype
= st.nextToken
();
193 end.set
(reader.getPosition
());
195 case StreamTokenizer.TT_EOF
:
197 case StreamTokenizer.TT_EOL
:
201 case StreamTokenizer.TT_WORD
:
202 yylval = new Integer
(st.sval
);
203 end.set
(reader.getPreviousPosition
());
226 throw new AssertionError
("invalid character: " + ttype
);
232 * A class defining a point in the input.
236 public
int column
= 1;
243 public Position
(int l
, int t
) {
248 public Position
(Position p
) {
253 public
void set
(Position p
) {
258 public boolean equals
(Position l
) {
259 return l.line
== line
&& l.column
== column
;
262 public String toString
() {
263 return Integer.toString
(line
) + "." + Integer.toString
(column
);
270 public
int column
() {
276 * A Stream reader that keeps track of the current Position.
278 class PositionReader extends BufferedReader
{
280 private Position position
= new Position
();
281 // Position before the latest call to "read", i.e. position
282 // of the last character of the current token.
283 private Position previousPosition
= new Position
();
285 public PositionReader
(Reader reader
) {
289 public
int read
() throws IOException
{
290 previousPosition.set
(position
);
291 int res
= super.read
();
294 if
(c
== '\r' || c
== '\n') {
298 position.column
+= 1;
304 public Position getPosition
() {
308 public Position getPreviousPosition
() {
309 return previousPosition
;