1 /* Parser and scanner for calc in D. -*- D -*-
3 Copyright (C) 2018-2022 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.push
-pull push
24 %define api.token.constructor
25 %define api.value.type
union
26 %define parse.
error detailed
31 /* Bison Declarations */
39 %token
<int> NUM
"number"
41 %printer
{ yyo.write
($$
); } <int>
45 %precedence UNARY
/* unary operators */
56 | exp EOL
{ writeln
($exp); }
57 |
error EOL
{ yyerrok(); }
62 | exp
"+" exp
{ $$
= $1 + $3; }
63 | exp
"-" exp
{ $$
= $1 - $3; }
64 | exp
"*" exp
{ $$
= $1 * $3; }
65 | exp
"/" exp
{ $$
= $1 / $3; }
66 |
"+" exp %prec UNARY
{ $$
= $2; }
67 |
"-" exp %prec UNARY
{ $$
= -$2; }
68 |
"(" exp
")" { $$
= $2; }
72 import std.range.primitives
;
75 auto calcLexer
(R
)(R range
)
76 if
(isInputRange
!R
&& is
(ElementType
!R
: dchar
))
78 return new CalcLexer
!R
(range
);
81 auto calcLexer
(File f
)
83 import std.algorithm
: map
, joiner
;
84 import std.utf
: byDchar
;
86 return f.byChunk
(1024) // avoid making a syscall roundtrip per char
87 .map
!(chunk
=> cast
(char[]) chunk
) // because byChunk returns ubyte[]
88 .joiner
// combine chunks into a single virtual range of char
89 .calcLexer
; // forward to other overload
92 class CalcLexer
(R
) : Lexer
93 if
(isInputRange
!R
&& is
(ElementType
!R
: dchar
))
97 this
(R r
) { input
= r
; }
101 // Should be a local in main, shared with %parse-param.
104 void yyerror(const Location loc
, string s
)
107 stderr.writeln
(loc.toString
(), ": ", s
);
112 import std.uni
: isWhite
, isNumber
;
114 // Skip initial spaces
115 while
(!input.empty
&& input.front
!= '\n' && isWhite
(input.front
))
117 location.end.column
++;
123 return Symbol.YYEOF
(location
);
126 if
(input.front.isNumber
)
128 import std.compiler
: version_minor
;
129 static if
(version_minor
>= 95)
131 // from Dlang v2.095.0 onwards std.conv.parse reports
132 // the number of consumed characters
133 import std.typecons
: Flag
, Yes
;
134 import std.conv
: parse
;
135 auto parsed
= parse
!(int, R
, Yes.doCount
)(input
);
136 int ival
= parsed.data
;
137 location.end.column
+= cast
(int) parsed.count
;
142 import std.conv
: parse
;
143 int ival
= input.parse
!int;
144 while
(!input.empty
&& copy.front
!= input.front
)
146 location.end.column
++;
150 return Symbol.NUM
(ival
, location
);
153 // Individual characters
154 auto ch
= input.front
;
156 location.end.column
++;
159 case
'+': return Symbol.PLUS
(location
);
160 case
'-': return Symbol.MINUS
(location
);
161 case
'*': return Symbol.STAR
(location
);
162 case
'/': return Symbol.SLASH
(location
);
163 case
'(': return Symbol.LPAR
(location
);
164 case
')': return Symbol.RPAR
(location
);
168 location.end.column
= 1;
169 return Symbol.EOL
(location
);
178 auto l
= calcLexer
(stdin
);
179 auto p
= new Calc
(l
);
180 import core.stdc.stdlib
: getenv
;
181 if
(getenv
("YYDEBUG"))
185 status
= p.pushParse
(l.
yylex());
186 } while
(status
== PUSH_MORE
);
187 return l.exit_status
;