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 // Customized syntax error messages (see reportSyntaxError)...
27 %define parse.
error custom
29 // ... with locations...
32 // ... and accurate list of expected tokens.
33 %define parse.lac full
38 import java.io.BufferedReader
;
39 import java.io.IOException
;
40 import java.io.InputStream
;
41 import java.io.InputStreamReader
;
42 import java.io.Reader
;
43 import java.io.StreamTokenizer
;
44 import java.nio.CharBuffer
;
48 public
static void main
(String
[] args
) throws IOException
{
49 CalcLexer scanner
= new CalcLexer
(System.in
);
50 Calc parser
= new Calc
(scanner
);
51 for
(String arg
: args
)
53 parser.setDebugLevel
(1);
56 int token
= scanner.getToken
();
57 Object lval
= scanner.getValue
();
58 Calc.Location yyloc
= scanner.getLocation
();
59 status
= parser.push_parse
(token
, lval
, yyloc
);
60 } while
(status
== Calc.YYPUSH_MORE
);
61 if
(status
!= Calc.
YYACCEPT)
65 static String i18n
(String s
) {
70 /* Bison Declarations */
86 %nonassoc
"=" /* comparison */
89 %precedence NEG
/* negation--unary minus */
90 %right
"^" /* exponentiation */
101 | exp EOL
{ System.out.println
($exp); }
109 if
($1.intValue
() != $3.intValue
())
110 yyerror(@$
, "calc: error: " + $1 + " != " + $3);
112 | exp
"+" exp
{ $$
= $1 + $3; }
113 | exp
"-" exp
{ $$
= $1 - $3; }
114 | exp
"*" exp
{ $$
= $1 * $3; }
115 | exp
"/" exp
{ $$
= $1 / $3; }
116 |
"-" exp %prec NEG
{ $$
= -$2; }
117 | exp
"^" exp
{ $$
= (int) Math.pow
($1, $3); }
118 |
"(" exp
")" { $$
= $2; }
119 |
"(" error ")" { $$
= 1111; }
120 |
"!" { $$
= 0; return
YYERROR; }
121 |
"-" error { $$
= 0; return
YYERROR; }
125 class CalcLexer implements Calc.Lexer
{
128 PositionReader reader
;
130 public CalcLexer
(InputStream is
) {
131 reader
= new PositionReader
(new InputStreamReader
(is
));
132 st
= new StreamTokenizer
(reader
);
134 st.eolIsSignificant
(true
);
135 st.wordChars
('0', '9');
138 Position start
= new Position
(1, 0);
139 Position end
= new Position
(1, 0);
142 * The location of the last token read.
143 * Implemented with getStartPos and getEndPos in pull parsers.
145 public Calc.Location getLocation
() {
146 return new Calc.Location
(new Position
(start
), new Position
(end
));
150 * Build and emit a syntax error message.
152 public
void reportSyntaxError
(Calc.Context ctx
) {
153 System.err.print
(ctx.getLocation
() + ": syntax error");
155 final
int TOKENMAX
= 10;
156 Calc.SymbolKind
[] arg
= new Calc.SymbolKind
[TOKENMAX
];
157 int n
= ctx.getExpectedTokens
(arg
, TOKENMAX
);
158 for
(int i
= 0; i
< n
; ++i
)
159 System.err.print
((i
== 0 ?
": expected " : " or ")
163 Calc.SymbolKind lookahead
= ctx.getToken
();
164 if
(lookahead
!= null
)
165 System.err.print
(" before " + lookahead.getName
());
167 System.err.println
("");
171 * Emit an error referring to the given location in a user-defined way.
173 * @@param loc The location of the element to which the
174 * error message is related.
175 * @@param msg The string for the error message.
177 public
void yyerror(Calc.Location loc
, String msg
) {
179 System.err.println
(msg
);
181 System.err.println
(loc
+ ": " + msg
);
187 * The value of the last token read. Called getLVal in pull parsers.
189 public Object getValue
() {
194 * Fetch the next token. Called yylex in pull parsers.
196 public
int getToken
() throws IOException
{
197 start.set
(reader.getPosition
());
198 int ttype
= st.nextToken
();
199 end.set
(reader.getPosition
());
201 case StreamTokenizer.TT_EOF
:
203 case StreamTokenizer.TT_EOL
:
207 case StreamTokenizer.TT_WORD
:
208 yylval = Integer.parseInt
(st.sval
);
209 end.set
(reader.getPreviousPosition
());
232 throw new AssertionError
("invalid character: " + ttype
);
238 * A class defining a point in the input.
242 public
int column
= 1;
249 public Position
(int l
, int t
) {
254 public Position
(Position p
) {
259 public
void set
(Position p
) {
264 public boolean equals
(Position l
) {
265 return l.line
== line
&& l.column
== column
;
268 public String toString
() {
269 return Integer.toString
(line
) + "." + Integer.toString
(column
);
276 public
int column
() {
282 * A Stream reader that keeps track of the current Position.
284 class PositionReader extends BufferedReader
{
286 private Position position
= new Position
();
287 // Position before the latest call to "read", i.e. position
288 // of the last character of the current token.
289 private Position previousPosition
= new Position
();
291 public PositionReader
(Reader reader
) {
295 public
int read
() throws IOException
{
296 previousPosition.set
(position
);
297 int res
= super.read
();
300 if
(c
== '\r' || c
== '\n') {
304 position.column
+= 1;
310 public Position getPosition
() {
314 public Position getPreviousPosition
() {
315 return previousPosition
;