1 /* Parser and scanner for calc in D. -*- D -*-
3 Copyright (C) 2018-2020 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 <http://www.gnu.org/licenses/>. */
22 %define api.parser.class
{Calc
}
23 %define parse.
error verbose
31 /* Bison Declarations */
39 %token
<ival
> NUM
"number"
44 %precedence UNARY
/* unary operators */
55 | exp EOL
{ writeln
($exp); }
56 |
error EOL
{ yyerrok(); }
61 | exp
"+" exp
{ $$
= $1 + $3; }
62 | exp
"-" exp
{ $$
= $1 - $3; }
63 | exp
"*" exp
{ $$
= $1 * $3; }
64 | exp
"/" exp
{ $$
= $1 / $3; }
65 |
"+" exp %prec UNARY
{ $$
= $2; }
66 |
"-" exp %prec UNARY
{ $$
= -$2; }
67 |
"(" exp
")" { $$
= $2; }
71 import std.range.primitives
;
74 auto calcLexer
(R
)(R range
)
75 if
(isInputRange
!R
&& is
(ElementType
!R
: dchar
))
77 return new CalcLexer
!R
(range
);
80 auto calcLexer
(File f
)
82 import std.algorithm
: map
, joiner
;
83 import std.utf
: byDchar
;
85 return f.byChunk
(1024) // avoid making a syscall roundtrip per char
86 .map
!(chunk
=> cast
(char[]) chunk
) // because byChunk returns ubyte[]
87 .joiner
// combine chunks into a single virtual range of char
88 .calcLexer
; // forward to other overload
91 class CalcLexer
(R
) : Lexer
92 if
(isInputRange
!R
&& is
(ElementType
!R
: dchar
))
96 this
(R r
) { input
= r
; }
100 // Should be a local in main, shared with %parse-param.
103 void yyerror(const YYLocation loc
, string s
)
106 stderr.writeln
(loc.toString
(), ": ", s
);
109 YYSemanticType semanticVal_
;
111 public final YYSemanticType semanticVal
()
118 import std.uni
: isWhite
, isNumber
;
120 // Skip initial spaces
121 while
(!input.empty
&& input.front
!= '\n' && isWhite
(input.front
))
123 location.begin
= location.end
;
124 location.end.column
++;
129 return Symbol
(TokenKind.YYEOF
, location
);
132 if
(input.front.isNumber
)
136 import std.conv
: parse
;
137 semanticVal_.ival
= input.parse
!int;
138 while
(!input.empty
&& copy.front
!= input.front
)
143 location.begin
= location.end
;
144 location.end.column
+= lenChars
;
145 return Symbol
(TokenKind.NUM
, semanticVal_.ival
, location
);
148 // Individual characters
149 auto ch
= input.front
;
151 location.begin
= location.end
;
152 location.end.column
++;
155 case
'+': return Symbol
(TokenKind.PLUS
, location
);
156 case
'-': return Symbol
(TokenKind.MINUS
, location
);
157 case
'*': return Symbol
(TokenKind.STAR
, location
);
158 case
'/': return Symbol
(TokenKind.SLASH
, location
);
159 case
'(': return Symbol
(TokenKind.LPAR
, location
);
160 case
')': return Symbol
(TokenKind.RPAR
, location
);
164 location.end.column
= 1;
165 return Symbol
(TokenKind.EOL
, location
);
171 YYPosition startPos
() const
173 return location.begin
;
176 YYPosition endPos
() const
184 auto l
= calcLexer
(stdin
);
185 auto p
= new Calc
(l
);
187 return l.exit_status
;