blob: cc09dbeb03f6a0372742901c949ea6fb985e0de2 [file] [log] [blame]
Chris Lattner22eb9722006-06-18 05:43:12 +00001//===--- PPExpressions.cpp - Preprocessor Expression Evaluation -----------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Chris Lattner80965422006-07-04 18:03:19 +000010// This file implements the Preprocessor::EvaluateDirectiveExpression method,
11// which parses and evaluates integer constant expressions for #if directives.
Chris Lattner22eb9722006-06-18 05:43:12 +000012//
13//===----------------------------------------------------------------------===//
14//
15// FIXME: implement testing for asserts.
16// FIXME: Parse integer constants correctly. Reject 123.0, etc.
17// FIXME: Track signed/unsigned correctly.
18// FIXME: Track and report integer overflow correctly.
19//
20//===----------------------------------------------------------------------===//
21
22#include "clang/Lex/Preprocessor.h"
Chris Lattnera78a97e2006-07-03 05:42:18 +000023#include "clang/Lex/MacroInfo.h"
Chris Lattner22eb9722006-06-18 05:43:12 +000024#include "clang/Basic/TokenKinds.h"
25#include "clang/Basic/Diagnostic.h"
26using namespace llvm;
27using namespace clang;
28
Chris Lattnere3519cc2006-07-04 18:11:39 +000029static bool EvaluateDirectiveSubExpr(int &LHS, unsigned MinPrec,
30 LexerToken &PeekTok, Preprocessor &PP);
Chris Lattner22eb9722006-06-18 05:43:12 +000031
Chris Lattnerb9d90f72006-07-04 18:32:03 +000032/// DefinedTracker - This struct is used while parsing expressions to keep track
33/// of whether !defined(X) has been seen.
34///
35/// With this simple scheme, we handle the basic forms:
36/// !defined(X) and !defined X
37/// but we also trivially handle (silly) stuff like:
38/// !!!defined(X) and +!defined(X) and !+!+!defined(X) and !(defined(X)).
39struct DefinedTracker {
40 /// Each time a Value is evaluated, it returns information about whether the
41 /// parsed value is of the form defined(X), !defined(X) or is something else.
42 enum TrackerState {
43 DefinedMacro, // defined(X)
44 NotDefinedMacro, // !defined(X)
45 Unknown // Something else.
46 } State;
47 /// TheMacro - When the state is DefinedMacro or NotDefinedMacro, this
48 /// indicates the macro that was checked.
49 IdentifierInfo *TheMacro;
50};
51
52
Chris Lattner22eb9722006-06-18 05:43:12 +000053
54/// EvaluateValue - Evaluate the token PeekTok (and any others needed) and
55/// return the computed value in Result. Return true if there was an error
Chris Lattnerb9d90f72006-07-04 18:32:03 +000056/// parsing. This function also returns information about the form of the
57/// expression in DT. See above for information on what DT means.
58static bool EvaluateValue(int &Result, LexerToken &PeekTok, DefinedTracker &DT,
59 Preprocessor &PP) {
Chris Lattner22eb9722006-06-18 05:43:12 +000060 Result = 0;
Chris Lattnerb9d90f72006-07-04 18:32:03 +000061 DT.State = DefinedTracker::Unknown;
Chris Lattner22eb9722006-06-18 05:43:12 +000062
63 // If this token's spelling is a pp-identifier, check to see if it is
64 // 'defined' or if it is a macro. Note that we check here because many
65 // keywords are pp-identifiers, so we can't check the kind.
Chris Lattnerb9d90f72006-07-04 18:32:03 +000066 if (IdentifierInfo *II = PeekTok.getIdentifierInfo()) {
Chris Lattner22eb9722006-06-18 05:43:12 +000067 // If this identifier isn't 'defined' and it wasn't macro expanded, it turns
68 // into a simple 0.
69 if (strcmp(II->getName(), "defined")) {
70 Result = 0;
Chris Lattnere3519cc2006-07-04 18:11:39 +000071 PP.Lex(PeekTok);
Chris Lattnercb283342006-06-18 06:48:37 +000072 return false;
Chris Lattner22eb9722006-06-18 05:43:12 +000073 }
74
75 // Handle "defined X" and "defined(X)".
Chris Lattner22eb9722006-06-18 05:43:12 +000076
Chris Lattnere3519cc2006-07-04 18:11:39 +000077 // Get the next token, don't expand it.
78 PP.LexUnexpandedToken(PeekTok);
Chris Lattner22eb9722006-06-18 05:43:12 +000079
80 // Two options, it can either be a pp-identifier or a (.
81 bool InParens = false;
82 if (PeekTok.getKind() == tok::l_paren) {
83 // Found a paren, remember we saw it and skip it.
84 InParens = true;
Chris Lattnere3519cc2006-07-04 18:11:39 +000085 PP.LexUnexpandedToken(PeekTok);
Chris Lattner22eb9722006-06-18 05:43:12 +000086 }
87
88 // If we don't have a pp-identifier now, this is an error.
89 if ((II = PeekTok.getIdentifierInfo()) == 0) {
Chris Lattnere3519cc2006-07-04 18:11:39 +000090 PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier);
Chris Lattner22eb9722006-06-18 05:43:12 +000091 return true;
92 }
93
94 // Otherwise, we got an identifier, is it defined to something?
95 Result = II->getMacroInfo() != 0;
Chris Lattnera78a97e2006-07-03 05:42:18 +000096
97 // If there is a macro, mark it used.
98 if (Result) II->getMacroInfo()->setIsUsed(true);
Chris Lattner22eb9722006-06-18 05:43:12 +000099
100 // Consume identifier.
Chris Lattnere3519cc2006-07-04 18:11:39 +0000101 PP.Lex(PeekTok);
Chris Lattner22eb9722006-06-18 05:43:12 +0000102
103 // If we are in parens, ensure we have a trailing ).
104 if (InParens) {
105 if (PeekTok.getKind() != tok::r_paren) {
Chris Lattnere3519cc2006-07-04 18:11:39 +0000106 PP.Diag(PeekTok, diag::err_pp_missing_rparen);
Chris Lattner22eb9722006-06-18 05:43:12 +0000107 return true;
108 }
109 // Consume the ).
Chris Lattnere3519cc2006-07-04 18:11:39 +0000110 PP.Lex(PeekTok);
Chris Lattner22eb9722006-06-18 05:43:12 +0000111 }
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000112
113 // Success, remember that we saw defined(X).
114 DT.State = DefinedTracker::DefinedMacro;
115 DT.TheMacro = II;
Chris Lattner22eb9722006-06-18 05:43:12 +0000116 return false;
117 }
118
119 switch (PeekTok.getKind()) {
120 default: // Non-value token.
Chris Lattnere3519cc2006-07-04 18:11:39 +0000121 PP.Diag(PeekTok, diag::err_pp_expr_bad_token);
Chris Lattner22eb9722006-06-18 05:43:12 +0000122 return true;
123 case tok::eom:
124 case tok::r_paren:
125 // If there is no expression, report and exit.
Chris Lattnere3519cc2006-07-04 18:11:39 +0000126 PP.Diag(PeekTok, diag::err_pp_expected_value_in_expr);
Chris Lattner22eb9722006-06-18 05:43:12 +0000127 return true;
128 case tok::numeric_constant: {
129 // FIXME: faster. FIXME: track signs.
Chris Lattnere3519cc2006-07-04 18:11:39 +0000130 std::string Spell = PP.getSpelling(PeekTok);
Chris Lattner22eb9722006-06-18 05:43:12 +0000131 // FIXME: COMPUTE integer constants CORRECTLY.
132 Result = atoi(Spell.c_str());
Chris Lattnere3519cc2006-07-04 18:11:39 +0000133 PP.Lex(PeekTok);
Chris Lattnercb283342006-06-18 06:48:37 +0000134 return false;
Chris Lattner22eb9722006-06-18 05:43:12 +0000135 }
136 case tok::l_paren:
Chris Lattnere3519cc2006-07-04 18:11:39 +0000137 PP.Lex(PeekTok); // Eat the (.
Chris Lattnercb283342006-06-18 06:48:37 +0000138 // Parse the value and if there are any binary operators involved, parse
139 // them.
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000140 if (EvaluateValue(Result, PeekTok, DT, PP)) return true;
Chris Lattner22eb9722006-06-18 05:43:12 +0000141
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000142 // If this is a silly value like (X), which doesn't need parens, check for
143 // !(defined X).
144 if (PeekTok.getKind() == tok::r_paren) {
145 // Just use DT unmodified as our result.
146 } else {
147 if (EvaluateDirectiveSubExpr(Result, 1, PeekTok, PP)) return true;
148
149 if (PeekTok.getKind() != tok::r_paren) {
150 PP.Diag(PeekTok, diag::err_pp_expected_rparen);
151 return true;
152 }
153 DT.State = DefinedTracker::Unknown;
Chris Lattner22eb9722006-06-18 05:43:12 +0000154 }
Chris Lattnere3519cc2006-07-04 18:11:39 +0000155 PP.Lex(PeekTok); // Eat the ).
Chris Lattner22eb9722006-06-18 05:43:12 +0000156 return false;
157
158 case tok::plus:
159 // Unary plus doesn't modify the value.
Chris Lattnere3519cc2006-07-04 18:11:39 +0000160 PP.Lex(PeekTok);
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000161 return EvaluateValue(Result, PeekTok, DT, PP);
Chris Lattner22eb9722006-06-18 05:43:12 +0000162 case tok::minus:
Chris Lattnere3519cc2006-07-04 18:11:39 +0000163 PP.Lex(PeekTok);
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000164 if (EvaluateValue(Result, PeekTok, DT, PP)) return true;
Chris Lattner22eb9722006-06-18 05:43:12 +0000165 Result = -Result;
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000166 DT.State = DefinedTracker::Unknown;
Chris Lattner22eb9722006-06-18 05:43:12 +0000167 return false;
168
169 case tok::tilde:
Chris Lattnere3519cc2006-07-04 18:11:39 +0000170 PP.Lex(PeekTok);
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000171 if (EvaluateValue(Result, PeekTok, DT, PP)) return true;
Chris Lattner22eb9722006-06-18 05:43:12 +0000172 Result = ~Result;
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000173 DT.State = DefinedTracker::Unknown;
Chris Lattner22eb9722006-06-18 05:43:12 +0000174 return false;
175
176 case tok::exclaim:
Chris Lattnere3519cc2006-07-04 18:11:39 +0000177 PP.Lex(PeekTok);
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000178 if (EvaluateValue(Result, PeekTok, DT, PP)) return true;
Chris Lattner22eb9722006-06-18 05:43:12 +0000179 Result = !Result;
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000180
181 if (DT.State == DefinedTracker::DefinedMacro)
182 DT.State = DefinedTracker::NotDefinedMacro;
183 else if (DT.State == DefinedTracker::NotDefinedMacro)
184 DT.State = DefinedTracker::DefinedMacro;
Chris Lattner22eb9722006-06-18 05:43:12 +0000185 return false;
186
187 // FIXME: Handle #assert
188 }
189}
190
191
192
193/// getPrecedence - Return the precedence of the specified binary operator
194/// token. This returns:
195/// ~0 - Invalid token.
196/// 15 - *,/,%
197/// 14 - -,+
198/// 13 - <<,>>
199/// 12 - >=, <=, >, <
200/// 11 - ==, !=
201/// 10 - <?, >? min, max (GCC extensions)
202/// 9 - &
203/// 8 - ^
204/// 7 - |
205/// 6 - &&
206/// 5 - ||
207/// 4 - ?
208/// 3 - :
209/// 0 - eom, )
210static unsigned getPrecedence(tok::TokenKind Kind) {
211 switch (Kind) {
212 default: return ~0U;
213 case tok::percent:
214 case tok::slash:
215 case tok::star: return 15;
216 case tok::plus:
217 case tok::minus: return 14;
218 case tok::lessless:
219 case tok::greatergreater: return 13;
220 case tok::lessequal:
221 case tok::less:
222 case tok::greaterequal:
223 case tok::greater: return 12;
224 case tok::exclaimequal:
225 case tok::equalequal: return 11;
226 case tok::lessquestion:
227 case tok::greaterquestion: return 10;
228 case tok::amp: return 9;
229 case tok::caret: return 8;
230 case tok::pipe: return 7;
231 case tok::ampamp: return 6;
232 case tok::pipepipe: return 5;
233 case tok::question: return 4;
234 case tok::colon: return 3;
235 case tok::comma: return 2;
236 case tok::r_paren: return 0; // Lowest priority, end of expr.
237 case tok::eom: return 0; // Lowest priority, end of macro.
238 }
239}
240
241
242/// EvaluateDirectiveSubExpr - Evaluate the subexpression whose first token is
243/// PeekTok, and whose precedence is PeekPrec.
Chris Lattnere3519cc2006-07-04 18:11:39 +0000244static bool EvaluateDirectiveSubExpr(int &LHS, unsigned MinPrec,
245 LexerToken &PeekTok, Preprocessor &PP) {
Chris Lattner22eb9722006-06-18 05:43:12 +0000246 unsigned PeekPrec = getPrecedence(PeekTok.getKind());
247 // If this token isn't valid, report the error.
248 if (PeekPrec == ~0U) {
Chris Lattnere3519cc2006-07-04 18:11:39 +0000249 PP.Diag(PeekTok, diag::err_pp_expr_bad_token);
Chris Lattner22eb9722006-06-18 05:43:12 +0000250 return true;
251 }
252
253 while (1) {
254 // If this token has a lower precedence than we are allowed to parse, return
255 // it so that higher levels of the recursion can parse it.
256 if (PeekPrec < MinPrec)
257 return false;
258
259 tok::TokenKind Operator = PeekTok.getKind();
260
261 // Consume the operator, saving the operator token for error reporting.
262 LexerToken OpToken = PeekTok;
Chris Lattnere3519cc2006-07-04 18:11:39 +0000263 PP.Lex(PeekTok);
Chris Lattner22eb9722006-06-18 05:43:12 +0000264
265 int RHS;
266 // Parse the RHS of the operator.
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000267 DefinedTracker DT;
268 if (EvaluateValue(RHS, PeekTok, DT, PP)) return true;
Chris Lattner22eb9722006-06-18 05:43:12 +0000269
270 // Remember the precedence of this operator and get the precedence of the
271 // operator immediately to the right of the RHS.
272 unsigned ThisPrec = PeekPrec;
273 PeekPrec = getPrecedence(PeekTok.getKind());
274
275 // If this token isn't valid, report the error.
276 if (PeekPrec == ~0U) {
Chris Lattnere3519cc2006-07-04 18:11:39 +0000277 PP.Diag(PeekTok, diag::err_pp_expr_bad_token);
Chris Lattner22eb9722006-06-18 05:43:12 +0000278 return true;
279 }
280
281 bool isRightAssoc = Operator == tok::question;
282
283 // Get the precedence of the operator to the right of the RHS. If it binds
284 // more tightly with RHS than we do, evaluate it completely first.
285 if (ThisPrec < PeekPrec ||
286 (ThisPrec == PeekPrec && isRightAssoc)) {
Chris Lattnere3519cc2006-07-04 18:11:39 +0000287 if (EvaluateDirectiveSubExpr(RHS, ThisPrec+1, PeekTok, PP))
Chris Lattner22eb9722006-06-18 05:43:12 +0000288 return true;
289 PeekPrec = getPrecedence(PeekTok.getKind());
290 }
291 assert(PeekPrec <= ThisPrec && "Recursion didn't work!");
292
293 switch (Operator) {
294 default: assert(0 && "Unknown operator token!");
295 case tok::percent:
296 if (RHS == 0) {
Chris Lattnere3519cc2006-07-04 18:11:39 +0000297 PP.Diag(OpToken, diag::err_pp_remainder_by_zero);
Chris Lattner22eb9722006-06-18 05:43:12 +0000298 return true;
299 }
300 LHS %= RHS;
301 break;
302 case tok::slash:
303 if (RHS == 0) {
Chris Lattnere3519cc2006-07-04 18:11:39 +0000304 PP.Diag(OpToken, diag::err_pp_division_by_zero);
Chris Lattner22eb9722006-06-18 05:43:12 +0000305 return true;
306 }
307 LHS /= RHS;
308 break;
309 case tok::star : LHS *= RHS; break;
310 case tok::lessless: LHS << RHS; break; // FIXME: shift amt overflow?
311 case tok::greatergreater: LHS >> RHS; break; // FIXME: signed vs unsigned
312 case tok::plus : LHS += RHS; break;
313 case tok::minus: LHS -= RHS; break;
314 case tok::lessequal: LHS = LHS <= RHS; break;
315 case tok::less: LHS = LHS < RHS; break;
316 case tok::greaterequal: LHS = LHS >= RHS; break;
317 case tok::greater: LHS = LHS > RHS; break;
318 case tok::exclaimequal: LHS = LHS != RHS; break;
319 case tok::equalequal: LHS = LHS == RHS; break;
320 case tok::lessquestion: // Deprecation warning emitted by the lexer.
321 LHS = std::min(LHS, RHS);
322 break;
323 case tok::greaterquestion: // Deprecation warning emitted by the lexer.
324 LHS = std::max(LHS, RHS);
325 break;
326 case tok::amp: LHS &= RHS; break;
327 case tok::caret: LHS ^= RHS; break;
328 case tok::pipe: LHS |= RHS; break;
329 case tok::ampamp: LHS = LHS && RHS; break;
330 case tok::pipepipe: LHS = LHS || RHS; break;
331 case tok::comma:
Chris Lattnere3519cc2006-07-04 18:11:39 +0000332 PP.Diag(OpToken, diag::ext_pp_comma_expr);
Chris Lattner22eb9722006-06-18 05:43:12 +0000333 LHS = RHS; // LHS = LHS,RHS -> RHS.
334 break;
335 case tok::question: {
336 // Parse the : part of the expression.
337 if (PeekTok.getKind() != tok::colon) {
Chris Lattnere3519cc2006-07-04 18:11:39 +0000338 PP.Diag(OpToken, diag::err_pp_question_without_colon);
Chris Lattner22eb9722006-06-18 05:43:12 +0000339 return true;
340 }
341 // Consume the :.
Chris Lattnere3519cc2006-07-04 18:11:39 +0000342 PP.Lex(PeekTok);
Chris Lattner22eb9722006-06-18 05:43:12 +0000343
344 // Evaluate the value after the :.
345 int AfterColonVal = 0;
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000346 DefinedTracker DT;
347 if (EvaluateValue(AfterColonVal, PeekTok, DT, PP)) return true;
Chris Lattner22eb9722006-06-18 05:43:12 +0000348
349 // Parse anything after the : RHS that has a higher precedence than ?.
350 if (EvaluateDirectiveSubExpr(AfterColonVal, ThisPrec+1,
Chris Lattnere3519cc2006-07-04 18:11:39 +0000351 PeekTok, PP))
Chris Lattner22eb9722006-06-18 05:43:12 +0000352 return true;
353
354 // Now that we have the condition, the LHS and the RHS of the :, evaluate.
355 LHS = LHS ? RHS : AfterColonVal;
356
357 // Figure out the precedence of the token after the : part.
358 PeekPrec = getPrecedence(PeekTok.getKind());
359 break;
360 }
361 case tok::colon:
362 // Don't allow :'s to float around without being part of ?: exprs.
Chris Lattnere3519cc2006-07-04 18:11:39 +0000363 PP.Diag(OpToken, diag::err_pp_colon_without_question);
Chris Lattner22eb9722006-06-18 05:43:12 +0000364 return true;
365 }
366 }
367
368 return false;
369}
Chris Lattnere3519cc2006-07-04 18:11:39 +0000370
371/// EvaluateDirectiveExpression - Evaluate an integer constant expression that
372/// may occur after a #if or #elif directive. If the expression is equivalent
373/// to "!defined(X)" return X in IfNDefMacro.
374bool Preprocessor::
375EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) {
376 // Peek ahead one token.
377 LexerToken Tok;
378 Lex(Tok);
379
380 int ResVal = 0;
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000381 DefinedTracker DT;
382 if (EvaluateValue(ResVal, Tok, DT, *this)) {
Chris Lattnere3519cc2006-07-04 18:11:39 +0000383 // Parse error, skip the rest of the macro line.
384 if (Tok.getKind() != tok::eom)
385 DiscardUntilEndOfDirective();
386 return false;
387 }
388
389 // If we are at the end of the expression after just parsing a value, there
390 // must be no (unparenthesized) binary operators involved, so we can exit
391 // directly.
392 if (Tok.getKind() == tok::eom) {
Chris Lattnerb9d90f72006-07-04 18:32:03 +0000393 // If the expression we parsed was of the form !defined(macro), return the
394 // macro in IfNDefMacro.
395 if (DT.State == DefinedTracker::NotDefinedMacro)
396 IfNDefMacro = DT.TheMacro;
397
Chris Lattnere3519cc2006-07-04 18:11:39 +0000398 return ResVal != 0;
399 }
400
401 // Otherwise, we must have a binary operator (e.g. "#if 1 < 2"), so parse the
402 // operator and the stuff after it.
403 if (EvaluateDirectiveSubExpr(ResVal, 1, Tok, *this)) {
404 // Parse error, skip the rest of the macro line.
405 if (Tok.getKind() != tok::eom)
406 DiscardUntilEndOfDirective();
407 return false;
408 }
409
410 // If we aren't at the tok::eom token, something bad happened, like an extra
411 // ')' token.
412 if (Tok.getKind() != tok::eom) {
413 Diag(Tok, diag::err_pp_expected_eol);
414 DiscardUntilEndOfDirective();
415 }
416
417 return ResVal != 0;
418}
419