Skip to content

Commit 4d8de10

Browse files
committed
Parse expressions in preprocessor #if statement
1 parent 22decdc commit 4d8de10

File tree

5 files changed

+53409
-48261
lines changed

5 files changed

+53409
-48261
lines changed

corpus/preprocessor.txt

+25-8
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ int b;
107107
name: (identifier)
108108
value: (preproc_arg))
109109
alternative: (preproc_elif
110-
condition: (preproc_arg)
110+
condition: (preproc_condition
111+
(preproc_expression
112+
(preproc_defined (identifier))))
111113
alternative: (preproc_else
112114
(declaration
113115
type: (primitive_type)
@@ -140,11 +142,23 @@ General if blocks
140142
---
141143

142144
(translation_unit
143-
(preproc_if (preproc_arg)
145+
(preproc_if
146+
(preproc_condition
147+
(preproc_expression
148+
(preproc_binary_expression
149+
(preproc_expression
150+
(preproc_defined (identifier)))
151+
(preproc_expression
152+
(preproc_defined (identifier))))))
144153
(preproc_def (identifier) (preproc_arg))
145-
(preproc_elif (preproc_arg)
154+
(preproc_elif
155+
(preproc_condition
156+
(preproc_expression (preproc_defined (identifier))))
146157
(preproc_def (identifier))
147-
(preproc_elif (preproc_arg)
158+
(preproc_elif
159+
(preproc_condition
160+
(preproc_expression
161+
(preproc_unary_expression (preproc_expression (preproc_defined (identifier))))))
148162
(preproc_def (identifier))
149163
(preproc_else
150164
(preproc_include (system_lib_string)))))))
@@ -179,15 +193,18 @@ int main() {
179193
(function_declarator (identifier) (parameter_list))
180194
(compound_statement
181195
(preproc_if
182-
(preproc_arg)
196+
(preproc_condition (preproc_expression (identifier)))
183197
(expression_statement (call_expression (identifier) (argument_list (string_literal))))
184198
(preproc_else
185199
(expression_statement (call_expression (identifier) (argument_list (string_literal))))))
186-
(preproc_if (preproc_arg)
200+
(preproc_if
201+
(preproc_condition (preproc_expression (identifier)))
187202
(return_statement (number_literal))
188-
(preproc_elif (preproc_arg)
203+
(preproc_elif
204+
(preproc_condition (preproc_expression (identifier)))
189205
(return_statement (number_literal))
190-
(preproc_elif (preproc_arg)
206+
(preproc_elif
207+
(preproc_condition (preproc_expression (identifier)))
191208
(return_statement (number_literal))
192209
(preproc_else
193210
(return_statement (number_literal)))))))))

grammar.js

+74-2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ module.exports = grammar({
4444
[$._type_specifier, $._expression, $.macro_type_specifier],
4545
[$._type_specifier, $.macro_type_specifier],
4646
[$.sized_type_specifier],
47+
[$.preproc_expression],
4748
],
4849

4950
word: $ => $.identifier,
@@ -104,6 +105,77 @@ module.exports = grammar({
104105
preproc_directive: $ => /#[ \t]*[a-zA-Z]\w*/,
105106
preproc_arg: $ => token(prec(-1, repeat1(/.|\\\r?\n/))),
106107

108+
line_continuation: $ => token(
109+
/\\\r?\n/
110+
),
111+
112+
preproc_condition: $ => seq(
113+
$.preproc_expression,
114+
'\n',
115+
),
116+
117+
preproc_expression: $ => seq(
118+
optional($.line_continuation),
119+
choice(
120+
$.identifier,
121+
prec(PREC.CALL, seq($.identifier, '(', commaSep($.preproc_expression), ')')),
122+
$.number_literal,
123+
$.char_literal,
124+
$.preproc_unary_expression,
125+
$.preproc_binary_expression,
126+
$.preproc_defined,
127+
$.preproc_parenthesized_expression,
128+
),
129+
optional($.line_continuation),
130+
),
131+
132+
preproc_parenthesized_expression: $ => seq(
133+
'(',
134+
$.preproc_expression,
135+
')'
136+
),
137+
138+
preproc_defined: $ => choice(
139+
prec(PREC.CALL, seq('defined', '(', $.identifier, ')')),
140+
seq('defined', $.identifier),
141+
),
142+
143+
preproc_unary_expression: $ => prec.left(PREC.UNARY, seq(
144+
field('operator', choice('!', '~', '-', '+')),
145+
field('argument', $.preproc_expression)
146+
)),
147+
148+
preproc_binary_expression: $ => {
149+
const table = [
150+
['+', PREC.ADD],
151+
['-', PREC.ADD],
152+
['*', PREC.MULTIPLY],
153+
['/', PREC.MULTIPLY],
154+
['%', PREC.MULTIPLY],
155+
['||', PREC.LOGICAL_OR],
156+
['&&', PREC.LOGICAL_AND],
157+
['|', PREC.INCLUSIVE_OR],
158+
['^', PREC.EXCLUSIVE_OR],
159+
['&', PREC.BITWISE_AND],
160+
['==', PREC.EQUAL],
161+
['!=', PREC.EQUAL],
162+
['>', PREC.RELATIONAL],
163+
['>=', PREC.RELATIONAL],
164+
['<=', PREC.RELATIONAL],
165+
['<', PREC.RELATIONAL],
166+
['<<', PREC.SHIFT],
167+
['>>', PREC.SHIFT],
168+
];
169+
170+
return choice(...table.map(([operator, precedence]) => {
171+
return prec.left(precedence, seq(
172+
field('left', $.preproc_expression),
173+
field('operator', operator),
174+
field('right', $.preproc_expression)
175+
))
176+
}));
177+
},
178+
107179
// Main Grammar
108180

109181
function_definition: $ => seq(
@@ -868,7 +940,7 @@ function preprocIf (suffix, content) {
868940
return {
869941
['preproc_if' + suffix]: $ => seq(
870942
preprocessor('if'),
871-
field('condition', $.preproc_arg),
943+
field('condition', $.preproc_condition),
872944
repeat(content($)),
873945
field('alternative', optional(elseBlock($))),
874946
preprocessor('endif')
@@ -889,7 +961,7 @@ function preprocIf (suffix, content) {
889961

890962
['preproc_elif' + suffix]: $ => seq(
891963
preprocessor('elif'),
892-
field('condition', $.preproc_arg),
964+
field('condition', $.preproc_condition),
893965
repeat(content($)),
894966
field('alternative', optional(elseBlock($))),
895967
)

0 commit comments

Comments
 (0)