Class: Rubycc::Preprocess::ConstantExpressionParser
- Inherits:
-
Object
- Object
- Rubycc::Preprocess::ConstantExpressionParser
- Defined in:
- lib/rubycc/preprocess/constant_expression.rb
Overview
Parses the controlling constant-expression of a "#if"/"#elif" (ISO C 6.10.1) into a Front::AST the shared ConstantEvaluator can fold. It runs over an already-neutralized Front::Token stream: "defined" has been folded to 1/0, macros have been expanded, and every surviving identifier has been turned into the integer 0 (6.10.1p4), so the only leaves that reach here are integer/character constants and parentheses.
The grammar admitted is exactly the integer constant-expression subset the preprocessor allows: unary "+ - ~ !", the binary arithmetic, shift, relational, equality and bitwise operators, "&&"/"||", and "?:". Cast, sizeof, comma and assignment are outside it; those spellings either arrive as a stray punctuator (comma, assignment) or, being keyword-spelled identifiers, have already collapsed to 0, and any leftover token is rejected. Rather than a method per precedence level, a single precedence table drives one climbing loop, so the whole binary grammar is one method.
Constant Summary collapse
- BINARY_OPERATORS =
Each binary operator's binding power (higher binds tighter) and the AST::Binary op it lowers to; "&&" and "||" carry :logical markers since they build their own short-circuiting nodes rather than an AST::Binary.
{ "*" => [11, :mul], "/" => [11, :div], "%" => [11, :mod], "+" => [10, :add], "-" => [10, :sub], "<<" => [9, :shl], ">>" => [9, :shr], "<" => [8, :lt], ">" => [8, :gt], "<=" => [8, :le], ">=" => [8, :ge], "==" => [7, :eq], "!=" => [7, :ne], "&" => [6, :and], "^" => [5, :xor], "|" => [4, :or], "&&" => [3, :logical_and], "||" => [2, :logical_or] }.freeze
- LOGICAL_OR_PRECEDENCE =
The lowest binding power in the table ("||"); the conditional operator sits just below it, so climbing from here collects every binary operator before "?:" is considered.
2- MAX_NESTING_DEPTH =
The recursion-depth ceiling, mirroring the main parser's guard: a hostile "#if (((...)))" or "#if !!!...1" would otherwise recurse until the Ruby stack overflows with a bare SystemStackError. This grammar is far lighter than the main parser's (a single precedence-climbing loop rather than a deep chain), so its stack gives out only around 2500 nested parentheses; 500 stops a pathological input after roughly 250 levels — an order of magnitude below that, and far above the trivial nesting any real controlling expression uses (well under ten).
500
Instance Method Summary collapse
-
#initialize(tokens, directive) ⇒ ConstantExpressionParser
constructor
A new instance of ConstantExpressionParser.
- #parse ⇒ Object
Constructor Details
#initialize(tokens, directive) ⇒ ConstantExpressionParser
Returns a new instance of ConstantExpressionParser.
56 57 58 59 60 61 62 63 |
# File 'lib/rubycc/preprocess/constant_expression.rb', line 56 def initialize(tokens, directive) @tokens = tokens @pos = 0 # The directive keyword ("if"/"elif"), used only to name diagnostics. @directive = directive # Live recursion depth, capped at MAX_NESTING_DEPTH by #with_nesting_guard. @depth = 0 end |
Instance Method Details
#parse ⇒ Object
65 66 67 68 69 70 71 72 |
# File 'lib/rubycc/preprocess/constant_expression.rb', line 65 def parse node = parse_conditional unless current.eof? raise_at(current, "extra tokens at end of ##{@directive} expression") end node end |