d: reduce verbosity for returning the location from yylex()
[bison.git] / examples / d / calc / calc.y
blobc9a7df964203649a5ca04c6b6a7b76990d50845a
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/>. */
20 %language "D"
22 %define api.parser.class {Calc}
23 %define parse.error verbose
25 %locations
27 %union {
28 int ival;
31 /* Bison Declarations */
32 %token PLUS "+"
33 MINUS "-"
34 STAR "*"
35 SLASH "/"
36 LPAR "("
37 RPAR ")"
38 EOL "end of line"
39 %token <ival> NUM "number"
40 %type <ival> exp
42 %left "-" "+"
43 %left "*" "/"
44 %precedence UNARY /* unary operators */
46 /* Grammar follows */
48 input:
49 line
50 | input line
53 line:
54 EOL
55 | exp EOL { writeln ($exp); }
56 | error EOL { yyerrok(); }
59 exp:
60 NUM { $$ = $1; }
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;
72 import std.stdio;
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))
94 R input;
96 this(R r) { input = r; }
98 YYLocation location;
100 // Should be a local in main, shared with %parse-param.
101 int exit_status = 0;
103 void yyerror(const YYLocation loc, string s)
105 exit_status = 1;
106 stderr.writeln(loc.toString(), ": ", s);
109 YYSemanticType semanticVal_;
111 public final YYSemanticType semanticVal()
113 return semanticVal_;
116 Symbol yylex()
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++;
125 input.popFront;
128 if (input.empty)
129 return Symbol(TokenKind.YYEOF, location);
131 // Numbers.
132 if (input.front.isNumber)
134 int lenChars = 0;
135 auto copy = input;
136 import std.conv : parse;
137 semanticVal_.ival = input.parse!int;
138 while (!input.empty && copy.front != input.front)
140 lenChars++;
141 copy.popFront;
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;
150 input.popFront;
151 location.begin = location.end;
152 location.end.column++;
153 switch (ch)
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);
161 case '\n':
163 location.end.line++;
164 location.end.column = 1;
165 return Symbol(TokenKind.EOL, location);
167 default: assert(0);
171 YYPosition startPos() const
173 return location.begin;
176 YYPosition endPos() const
178 return location.end;
182 int main()
184 auto l = calcLexer(stdin);
185 auto p = new Calc(l);
186 p.parse();
187 return l.exit_status;