1 /* Parser and scanner for calc in D. -*- D -*-
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 parse.
error verbose
29 /* Bison Declarations */
38 %token
<ival
> NUM
"number"
43 %precedence UNARY
/* unary operators */
54 | exp EOL
{ writeln
($exp); }
60 | exp
"+" exp
{ $$
= $1 + $3; }
61 | exp
"-" exp
{ $$
= $1 - $3; }
62 | exp
"*" exp
{ $$
= $1 * $3; }
63 | exp
"/" exp
{ $$
= $1 / $3; }
64 |
"+" exp %prec UNARY
{ $$
= -$2; }
65 |
"-" exp %prec UNARY
{ $$
= -$2; }
66 |
"(" exp
")" { $$
= $2; }
70 import std.range.primitives
;
73 auto calcLexer
(R
)(R range
)
74 if
(isInputRange
!R
&& is
(ElementType
!R
: dchar
))
76 return new CalcLexer
!R
(range
);
79 auto calcLexer
(File f
)
81 import std.algorithm
: map
, joiner
;
82 import std.utf
: byDchar
;
84 return f.byChunk
(1024) // avoid making a syscall roundtrip per char
85 .map
!(chunk
=> cast
(char[]) chunk
) // because byChunk returns ubyte[]
86 .joiner
// combine chunks into a single virtual range of char
87 .calcLexer
; // forward to other overload
90 class CalcLexer
(R
) : Lexer
91 if
(isInputRange
!R
&& is
(ElementType
!R
: dchar
))
95 this
(R r
) { input
= r
; }
97 // Should be a local in main, shared with %parse-param.
100 public
void yyerror (string s
)
106 YYSemanticType semanticVal_
;
108 public final @property YYSemanticType semanticVal
()
115 import std.uni
: isWhite
, isNumber
;
117 // Skip initial spaces
118 while
(!input.empty
&& input.front
!= '\n' && isWhite
(input.front
))
122 return TokenKind.YYEOF
;
125 if
(input.front.isNumber
)
127 import std.conv
: parse
;
128 semanticVal_.ival
= input.parse
!int;
129 return TokenKind.NUM
;
132 // Individual characters
133 auto ch
= input.front
;
137 case
'=': return TokenKind.EQ
;
138 case
'+': return TokenKind.PLUS
;
139 case
'-': return TokenKind.MINUS
;
140 case
'*': return TokenKind.STAR
;
141 case
'/': return TokenKind.SLASH
;
142 case
'(': return TokenKind.LPAR
;
143 case
')': return TokenKind.RPAR
;
144 case
'\n': return TokenKind.EOL
;
152 auto l
= calcLexer
(stdin
);
153 auto p
= new Calc
(l
);
155 return l.exit_status
;