1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
#include "cps/Diagnostics.h"
#include "cps/Parser.h"
#include "cps/FunctionAST.h"
#include <cstdio>
using namespace cps;
std::unique_ptr<StmtAST> Parser::ParseTryStmt() {
getNextToken();
auto Body = ParseBlock({tok_catch, tok_endtry});
if (CurTok != tok_catch) {
cps::sourceDiagnostic(Lex.getLine(), "error: Expected CATCH in TRY at line %d\n", Lex.getLine());
return nullptr;
}
getNextToken();
auto CatchBody = ParseBlock({tok_endtry, tok_catch});
if (CurTok != tok_endtry) {
cps::sourceDiagnostic(Lex.getLine(), "error: Expected ENDTRY after CATCH at line %d\n", Lex.getLine());
return nullptr;
}
getNextToken();
return std::make_unique<TryStmtAST>(std::move(Body), std::move(CatchBody));
}
std::unique_ptr<StmtAST> Parser::ParseIfStmt() {
getNextToken();
auto Cond = ParseExpression();
if (!Cond) return nullptr;
if (CurTok != tok_then) {
cps::sourceDiagnostic(Lex.getLine(), "error: expected THEN at line %d\n", Lex.getLine());
return nullptr;
}
getNextToken();
std::vector<std::unique_ptr<StmtAST>> ThenStmts = ParseBlock({tok_else, tok_endif});
std::vector<std::unique_ptr<StmtAST>> ElseStmts;
if (CurTok == tok_else) {
getNextToken();
ElseStmts = ParseBlock({tok_endif});
}
if (CurTok != tok_endif) {
cps::sourceDiagnostic(Lex.getLine(), "error: expected ENDIF at line %d\n", Lex.getLine());
return nullptr;
}
getNextToken();
return std::make_unique<IfStmtAST>(std::move(Cond), std::move(ThenStmts), std::move(ElseStmts));
}
std::unique_ptr<StmtAST> Parser::ParseWhileStmt() {
getNextToken();
auto Cond = ParseExpression();
if (!Cond) return nullptr;
if (CurTok == tok_identifier && Lex.IdentifierStr == "DO") getNextToken();
std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_endwhile});
if (CurTok != tok_endwhile) {
cps::sourceDiagnostic(Lex.getLine(), "error: expected ENDWHILE\n");
return nullptr;
}
getNextToken();
return std::make_unique<WhileStmtAST>(std::move(Cond), std::move(Body));
}
std::unique_ptr<StmtAST> Parser::ParseRepeatStmt() {
getNextToken();
std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_until});
if (CurTok != tok_until) {
cps::sourceDiagnostic(Lex.getLine(), "error: expected UNTIL\n");
return nullptr;
}
getNextToken();
auto Cond = ParseExpression();
if (!Cond) return nullptr;
return std::make_unique<RepeatStmtAST>(std::move(Body), std::move(Cond));
}
std::unique_ptr<StmtAST> Parser::ParseForStmt() {
getNextToken();
if (CurTok != tok_identifier) {
cps::sourceDiagnostic(Lex.getLine(), "error: expected identifier after FOR\n");
return nullptr;
}
std::string VarName = Lex.IdentifierStr;
getNextToken();
if (CurTok != tok_assign) {
cps::sourceDiagnostic(Lex.getLine(), "error: expected '<-' in FOR loop\n");
return nullptr;
}
getNextToken();
auto Start = ParseExpression();
if (!Start) return nullptr;
if (CurTok != tok_to) {
cps::sourceDiagnostic(Lex.getLine(), "error: expected TO in FOR loop\n");
return nullptr;
}
getNextToken();
auto End = ParseExpression();
if (!End) return nullptr;
std::unique_ptr<ExprAST> Step = nullptr;
if (CurTok == tok_step) {
getNextToken();
Step = ParseExpression();
if (!Step) return nullptr;
}
std::vector<std::unique_ptr<StmtAST>> Body = ParseBlock({tok_next});
if (CurTok != tok_next) {
cps::sourceDiagnostic(Lex.getLine(), "error: expected NEXT\n");
return nullptr;
}
getNextToken();
if (CurTok != tok_identifier) {
cps::sourceDiagnostic(Lex.getLine(), "error: expected identifier after NEXT (e.g., NEXT %s)\n", VarName.c_str());
return nullptr;
}
if (!sameIdentifier(Lex.IdentifierStr, VarName)) {
cps::sourceDiagnostic(Lex.getLine(), "error: NEXT identifier '%s' does not match FOR variable '%s'\n",
Lex.IdentifierStr.c_str(), VarName.c_str());
return nullptr;
}
getNextToken();
return std::make_unique<ForStmtAST>(VarName, std::move(Start), std::move(End), std::move(Step), std::move(Body));
}
// A label begins a source line and ends in ':' on that line. Lookahead
// preserves token payloads; assignments and statement keywords are not labels.
bool Parser::isCaseLabel() {
if (!StartsLine) return false;
int Line = Lex.getLine();
int Depth = 0;
for (unsigned I = 0;; ++I) {
int T = I == 0 ? CurTok : Lex.peekToken(I - 1);
int TokenLine = I == 0 ? Line : Lex.peekLine(I - 1);
if (TokenLine != Line) return false;
if (T == tok_colon) return Depth == 0;
switch (T) {
case '(': case '[': ++Depth; break;
case ')': case ']': if (--Depth < 0) return false; break;
case tok_identifier: case tok_number_int: case tok_number_real:
case tok_string_literal: case tok_char_literal: case tok_true: case tok_false:
case tok_integer_kw: case tok_real_kw: case tok_boolean_kw:
case tok_string_kw: case tok_char_kw: case tok_c_int: case tok_c_char:
case tok_c_string: case tok_c_double:
case tok_to: case tok_otherwise: case tok_and: case tok_or: case tok_not:
case tok_eq: case tok_ne: case tok_le: case tok_ge: case tok_div: case tok_mod:
case '+': case '-': case '*': case '/': case '&': case '^':
case '<': case '>': case '.': case ',': break;
default: return false;
}
}
}
bool Parser::atCaseBoundary() {
return !ParsingCaseLabel && !CaseBodyDepths.empty() &&
CaseBodyDepths.back() == BlockDepth && isCaseLabel();
}
std::unique_ptr<StmtAST> Parser::ParseCaseStmt() {
getNextToken();
if (CurTok != tok_of) {
cps::sourceDiagnostic(Lex.getLine(), "error: Expected OF after CASE at line %d\n", Lex.getLine());
return nullptr;
}
getNextToken();
if (CurTok != tok_identifier) {
cps::sourceDiagnostic(Lex.getLine(), "error: Expected identifier after CASE OF at line %d\n", Lex.getLine());
return nullptr;
}
std::string Selector = Lex.IdentifierStr;
getNextToken();
std::vector<CaseBranch> Branches;
bool SeenOtherwise = false;
while (CurTok != tok_endcase && CurTok != tok_eof) {
if (SeenOtherwise || !isCaseLabel()) {
cps::sourceDiagnostic(Lex.getLine(), "error: Expected CASE label on a new line (OTHERWISE must be last) at line %d\n", Lex.getLine());
return nullptr;
}
CaseBranch Branch;
Branch.Line = Lex.getLine();
if (CurTok == tok_otherwise) {
SeenOtherwise = true;
getNextToken();
} else {
bool Saved = ParsingCaseLabel;
ParsingCaseLabel = true;
Branch.Lower = ParseExpression();
if (Branch.Lower && CurTok == tok_to) {
getNextToken();
Branch.Upper = ParseExpression();
if (!Branch.Upper) Branch.Lower.reset();
}
ParsingCaseLabel = Saved;
if (!Branch.Lower) return nullptr;
}
if (CurTok != tok_colon) {
cps::sourceDiagnostic(Lex.getLine(), "error: Expected ':' after CASE label at line %d\n", Lex.getLine());
return nullptr;
}
getNextToken();
Branch.Body = ParseBlock({tok_endcase}, true);
Branches.push_back(std::move(Branch));
}
if (CurTok != tok_endcase || Branches.empty()) {
cps::sourceDiagnostic(Lex.getLine(), "error: Expected nonempty CASE and ENDCASE at line %d\n", Lex.getLine());
return nullptr;
}
getNextToken();
return std::make_unique<CaseStmtAST>(std::move(Selector), std::move(Branches));
}
|