Skip to content

Commit 004c054

Browse files
authored
Merge pull request #1811 from autoboosh/preprocessorfix
make preprocessor grammar more understandable (fixes #1769)
2 parents b57986b + bff6517 commit 004c054

15 files changed

+3165
-2860
lines changed

Rubberduck.Parsing/Grammar/VBALexer.cs

Lines changed: 1077 additions & 1141 deletions
Large diffs are not rendered by default.

Rubberduck.Parsing/Grammar/VBALexer.g4

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,11 @@ EACH : E A C H;
106106
ELSE : E L S E;
107107
ELSEIF : E L S E I F;
108108
EMPTY : E M P T Y;
109+
// Apparently END_ENUM and END_TYPE don't allow line continuations (in the VB editor)
109110
END_ENUM : E N D WS+ E N U M;
110111
END_FUNCTION : E N D (WS | LINE_CONTINUATION)+ F U N C T I O N;
111-
END_IF : E N D (WS | LINE_CONTINUATION)+ I F;
112+
// We allow "EndIf" without the whitespace as well for the preprocessor.
113+
END_IF : E N D (WS | LINE_CONTINUATION)* I F;
112114
END_PROPERTY : E N D (WS | LINE_CONTINUATION)+ P R O P E R T Y;
113115
END_SELECT : E N D (WS | LINE_CONTINUATION)+ S E L E C T;
114116
END_SUB : E N D (WS | LINE_CONTINUATION)+ S U B;
@@ -235,11 +237,6 @@ NEQ : '<>' | '><';
235237
PLUS : '+';
236238
POW : '^';
237239
RPAREN : ')';
238-
HASHCONST : WS* HASH CONST WS+;
239-
HASHIF : WS* HASH I F WS+;
240-
HASHELSEIF : WS* HASH E L S E I F WS+;
241-
HASHELSE : WS* HASH E L S E WS* (SINGLEQUOTE (LINE_CONTINUATION | ~[\r\n\u2028\u2029])*)? (NEWLINE | EOF);
242-
HASHENDIF : WS* HASH E N D WS* I F WS* (SINGLEQUOTE (LINE_CONTINUATION | ~[\r\n\u2028\u2029])*)? (NEWLINE | EOF);
243240
L_SQUARE_BRACKET : '[';
244241
R_SQUARE_BRACKET : ']';
245242
STRINGLITERAL : '"' (~["\r\n] | '""')* '"';

Rubberduck.Parsing/Grammar/VBAParser.cs

Lines changed: 44 additions & 51 deletions
Large diffs are not rendered by default.

Rubberduck.Parsing/Preprocessing/VBAConditionalCompilationParser.cs

Lines changed: 1700 additions & 1582 deletions
Large diffs are not rendered by default.

Rubberduck.Parsing/Preprocessing/VBAConditionalCompilationParser.g4

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,52 @@ options { tokenVocab = VBALexer; }
44

55
compilationUnit : ccBlock EOF;
66

7-
ccBlock : (ccConst | ccIfBlock | logicalLine)*;
8-
9-
ccConst : HASHCONST ccVarLhs WS+ EQ WS+ ccExpression ccEol;
10-
11-
logicalLine :
12-
~(HASHCONST | HASHIF | HASHELSEIF | HASHELSE | HASHENDIF)+
13-
| NEWLINE
7+
ccBlock :
8+
// We use the non-greedy operator so that we stop consuming EOFs as soon as possible.
9+
// EOFs can be used in other places than the start rule since they're "emitted as long as someone takes them".
10+
(ccConst | ccIfBlock | physicalLine)*?
1411
;
1512

13+
ccConst : WS* hashConst WS+ ccVarLhs WS* EQ WS* ccExpression ccEol;
1614
ccVarLhs : name;
1715

18-
ccExpression :
19-
LPAREN WS* ccExpression WS* RPAREN
20-
| ccExpression WS* POW WS* ccExpression
21-
| MINUS WS* ccExpression
22-
| ccExpression WS* (MULT | DIV) WS* ccExpression
23-
| ccExpression WS* INTDIV WS* ccExpression
24-
| ccExpression WS* MOD WS* ccExpression
25-
| ccExpression WS* (PLUS | MINUS) WS* ccExpression
26-
| ccExpression WS* AMPERSAND WS* ccExpression
27-
| ccExpression WS* (EQ | NEQ | LT | GT | LEQ | GEQ | LIKE | IS) WS* ccExpression
28-
| NOT WS* ccExpression
29-
| ccExpression WS* AND WS* ccExpression
30-
| ccExpression WS* OR WS* ccExpression
31-
| ccExpression WS* XOR WS* ccExpression
32-
| ccExpression WS* EQV WS* ccExpression
33-
| ccExpression WS* IMP WS* ccExpression
34-
| intrinsicFunction
35-
| literal
36-
| name;
37-
3816
ccIfBlock : ccIf ccBlock ccElseIfBlock* ccElseBlock? ccEndIf;
39-
40-
ccIf : HASHIF ccExpression WS+ THEN WS* ccEol;
41-
17+
ccIf : WS* hashIf WS+ ccExpression WS+ THEN ccEol;
4218
ccElseIfBlock : ccElseIf ccBlock;
43-
44-
ccElseIf : HASHELSEIF ccExpression WS+ THEN WS* ccEol;
45-
19+
ccElseIf : WS* hashElseIf WS+ ccExpression WS+ THEN ccEol;
4620
ccElseBlock : ccElse ccBlock;
21+
ccElse : WS* hashElse ccEol;
22+
ccEndIf : WS* hashEndIf ccEol;
23+
ccEol : WS* comment? (NEWLINE | EOF);
24+
// We use parser rules instead of tokens (such as HASHCONST) because
25+
// marked file numbers have a similar format and cause conflicts.
26+
hashConst : HASH CONST;
27+
hashIf : HASH IF;
28+
hashElseIf : HASH ELSEIF;
29+
hashElse : HASH ELSE;
30+
hashEndIf : HASH END_IF;
4731

48-
ccElse : HASHELSE;
32+
physicalLine : ~(NEWLINE | EOF)* (NEWLINE | EOF);
4933

50-
ccEndIf : HASHENDIF;
51-
52-
ccEol : comment? (NEWLINE | EOF);
34+
ccExpression :
35+
LPAREN WS* ccExpression WS* RPAREN
36+
| ccExpression WS* POW WS* ccExpression
37+
| MINUS WS* ccExpression
38+
| ccExpression WS* (MULT | DIV) WS* ccExpression
39+
| ccExpression WS* INTDIV WS* ccExpression
40+
| ccExpression WS* MOD WS* ccExpression
41+
| ccExpression WS* (PLUS | MINUS) WS* ccExpression
42+
| ccExpression WS* AMPERSAND WS* ccExpression
43+
| ccExpression WS* (EQ | NEQ | LT | GT | LEQ | GEQ | LIKE | IS) WS* ccExpression
44+
| NOT WS* ccExpression
45+
| ccExpression WS* AND WS* ccExpression
46+
| ccExpression WS* OR WS* ccExpression
47+
| ccExpression WS* XOR WS* ccExpression
48+
| ccExpression WS* EQV WS* ccExpression
49+
| ccExpression WS* IMP WS* ccExpression
50+
| intrinsicFunction
51+
| literal
52+
| name;
5353

5454
intrinsicFunction : intrinsicFunctionName LPAREN WS* ccExpression WS* RPAREN;
5555

Rubberduck.Parsing/Preprocessing/VBAConditionalCompilationParserBaseListener.cs

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,30 +47,30 @@ public virtual void EnterCcBlock([NotNull] VBAConditionalCompilationParser.CcBlo
4747
public virtual void ExitCcBlock([NotNull] VBAConditionalCompilationParser.CcBlockContext context) { }
4848

4949
/// <summary>
50-
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.logicalLine"/>.
50+
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.typeHint"/>.
5151
/// <para>The default implementation does nothing.</para>
5252
/// </summary>
5353
/// <param name="context">The parse tree.</param>
54-
public virtual void EnterLogicalLine([NotNull] VBAConditionalCompilationParser.LogicalLineContext context) { }
54+
public virtual void EnterTypeHint([NotNull] VBAConditionalCompilationParser.TypeHintContext context) { }
5555
/// <summary>
56-
/// Exit a parse tree produced by <see cref="VBAConditionalCompilationParser.logicalLine"/>.
56+
/// Exit a parse tree produced by <see cref="VBAConditionalCompilationParser.typeHint"/>.
5757
/// <para>The default implementation does nothing.</para>
5858
/// </summary>
5959
/// <param name="context">The parse tree.</param>
60-
public virtual void ExitLogicalLine([NotNull] VBAConditionalCompilationParser.LogicalLineContext context) { }
60+
public virtual void ExitTypeHint([NotNull] VBAConditionalCompilationParser.TypeHintContext context) { }
6161

6262
/// <summary>
63-
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.typeHint"/>.
63+
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.hashIf"/>.
6464
/// <para>The default implementation does nothing.</para>
6565
/// </summary>
6666
/// <param name="context">The parse tree.</param>
67-
public virtual void EnterTypeHint([NotNull] VBAConditionalCompilationParser.TypeHintContext context) { }
67+
public virtual void EnterHashIf([NotNull] VBAConditionalCompilationParser.HashIfContext context) { }
6868
/// <summary>
69-
/// Exit a parse tree produced by <see cref="VBAConditionalCompilationParser.typeHint"/>.
69+
/// Exit a parse tree produced by <see cref="VBAConditionalCompilationParser.hashIf"/>.
7070
/// <para>The default implementation does nothing.</para>
7171
/// </summary>
7272
/// <param name="context">The parse tree.</param>
73-
public virtual void ExitTypeHint([NotNull] VBAConditionalCompilationParser.TypeHintContext context) { }
73+
public virtual void ExitHashIf([NotNull] VBAConditionalCompilationParser.HashIfContext context) { }
7474

7575
/// <summary>
7676
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.literal"/>.
@@ -85,6 +85,19 @@ public virtual void EnterLiteral([NotNull] VBAConditionalCompilationParser.Liter
8585
/// <param name="context">The parse tree.</param>
8686
public virtual void ExitLiteral([NotNull] VBAConditionalCompilationParser.LiteralContext context) { }
8787

88+
/// <summary>
89+
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.hashConst"/>.
90+
/// <para>The default implementation does nothing.</para>
91+
/// </summary>
92+
/// <param name="context">The parse tree.</param>
93+
public virtual void EnterHashConst([NotNull] VBAConditionalCompilationParser.HashConstContext context) { }
94+
/// <summary>
95+
/// Exit a parse tree produced by <see cref="VBAConditionalCompilationParser.hashConst"/>.
96+
/// <para>The default implementation does nothing.</para>
97+
/// </summary>
98+
/// <param name="context">The parse tree.</param>
99+
public virtual void ExitHashConst([NotNull] VBAConditionalCompilationParser.HashConstContext context) { }
100+
88101
/// <summary>
89102
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.statementKeyword"/>.
90103
/// <para>The default implementation does nothing.</para>
@@ -228,6 +241,32 @@ public virtual void EnterForeignIdentifier([NotNull] VBAConditionalCompilationPa
228241
/// <param name="context">The parse tree.</param>
229242
public virtual void ExitForeignIdentifier([NotNull] VBAConditionalCompilationParser.ForeignIdentifierContext context) { }
230243

244+
/// <summary>
245+
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.hashElse"/>.
246+
/// <para>The default implementation does nothing.</para>
247+
/// </summary>
248+
/// <param name="context">The parse tree.</param>
249+
public virtual void EnterHashElse([NotNull] VBAConditionalCompilationParser.HashElseContext context) { }
250+
/// <summary>
251+
/// Exit a parse tree produced by <see cref="VBAConditionalCompilationParser.hashElse"/>.
252+
/// <para>The default implementation does nothing.</para>
253+
/// </summary>
254+
/// <param name="context">The parse tree.</param>
255+
public virtual void ExitHashElse([NotNull] VBAConditionalCompilationParser.HashElseContext context) { }
256+
257+
/// <summary>
258+
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.hashEndIf"/>.
259+
/// <para>The default implementation does nothing.</para>
260+
/// </summary>
261+
/// <param name="context">The parse tree.</param>
262+
public virtual void EnterHashEndIf([NotNull] VBAConditionalCompilationParser.HashEndIfContext context) { }
263+
/// <summary>
264+
/// Exit a parse tree produced by <see cref="VBAConditionalCompilationParser.hashEndIf"/>.
265+
/// <para>The default implementation does nothing.</para>
266+
/// </summary>
267+
/// <param name="context">The parse tree.</param>
268+
public virtual void ExitHashEndIf([NotNull] VBAConditionalCompilationParser.HashEndIfContext context) { }
269+
231270
/// <summary>
232271
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.ccExpression"/>.
233272
/// <para>The default implementation does nothing.</para>
@@ -358,6 +397,32 @@ public virtual void EnterComment([NotNull] VBAConditionalCompilationParser.Comme
358397
/// <param name="context">The parse tree.</param>
359398
public virtual void ExitComment([NotNull] VBAConditionalCompilationParser.CommentContext context) { }
360399

400+
/// <summary>
401+
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.hashElseIf"/>.
402+
/// <para>The default implementation does nothing.</para>
403+
/// </summary>
404+
/// <param name="context">The parse tree.</param>
405+
public virtual void EnterHashElseIf([NotNull] VBAConditionalCompilationParser.HashElseIfContext context) { }
406+
/// <summary>
407+
/// Exit a parse tree produced by <see cref="VBAConditionalCompilationParser.hashElseIf"/>.
408+
/// <para>The default implementation does nothing.</para>
409+
/// </summary>
410+
/// <param name="context">The parse tree.</param>
411+
public virtual void ExitHashElseIf([NotNull] VBAConditionalCompilationParser.HashElseIfContext context) { }
412+
413+
/// <summary>
414+
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.physicalLine"/>.
415+
/// <para>The default implementation does nothing.</para>
416+
/// </summary>
417+
/// <param name="context">The parse tree.</param>
418+
public virtual void EnterPhysicalLine([NotNull] VBAConditionalCompilationParser.PhysicalLineContext context) { }
419+
/// <summary>
420+
/// Exit a parse tree produced by <see cref="VBAConditionalCompilationParser.physicalLine"/>.
421+
/// <para>The default implementation does nothing.</para>
422+
/// </summary>
423+
/// <param name="context">The parse tree.</param>
424+
public virtual void ExitPhysicalLine([NotNull] VBAConditionalCompilationParser.PhysicalLineContext context) { }
425+
361426
/// <summary>
362427
/// Enter a parse tree produced by <see cref="VBAConditionalCompilationParser.ccConst"/>.
363428
/// <para>The default implementation does nothing.</para>

Rubberduck.Parsing/Preprocessing/VBAConditionalCompilationParserBaseVisitor.cs

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,26 @@ public partial class VBAConditionalCompilationParserBaseVisitor<Result> : Abstra
4444
public virtual Result VisitCcBlock([NotNull] VBAConditionalCompilationParser.CcBlockContext context) { return VisitChildren(context); }
4545

4646
/// <summary>
47-
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.logicalLine"/>.
47+
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.typeHint"/>.
4848
/// <para>
4949
/// The default implementation returns the result of calling <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
5050
/// on <paramref name="context"/>.
5151
/// </para>
5252
/// </summary>
5353
/// <param name="context">The parse tree.</param>
5454
/// <return>The visitor result.</return>
55-
public virtual Result VisitLogicalLine([NotNull] VBAConditionalCompilationParser.LogicalLineContext context) { return VisitChildren(context); }
55+
public virtual Result VisitTypeHint([NotNull] VBAConditionalCompilationParser.TypeHintContext context) { return VisitChildren(context); }
5656

5757
/// <summary>
58-
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.typeHint"/>.
58+
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.hashIf"/>.
5959
/// <para>
6060
/// The default implementation returns the result of calling <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
6161
/// on <paramref name="context"/>.
6262
/// </para>
6363
/// </summary>
6464
/// <param name="context">The parse tree.</param>
6565
/// <return>The visitor result.</return>
66-
public virtual Result VisitTypeHint([NotNull] VBAConditionalCompilationParser.TypeHintContext context) { return VisitChildren(context); }
66+
public virtual Result VisitHashIf([NotNull] VBAConditionalCompilationParser.HashIfContext context) { return VisitChildren(context); }
6767

6868
/// <summary>
6969
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.literal"/>.
@@ -76,6 +76,17 @@ public partial class VBAConditionalCompilationParserBaseVisitor<Result> : Abstra
7676
/// <return>The visitor result.</return>
7777
public virtual Result VisitLiteral([NotNull] VBAConditionalCompilationParser.LiteralContext context) { return VisitChildren(context); }
7878

79+
/// <summary>
80+
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.hashConst"/>.
81+
/// <para>
82+
/// The default implementation returns the result of calling <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
83+
/// on <paramref name="context"/>.
84+
/// </para>
85+
/// </summary>
86+
/// <param name="context">The parse tree.</param>
87+
/// <return>The visitor result.</return>
88+
public virtual Result VisitHashConst([NotNull] VBAConditionalCompilationParser.HashConstContext context) { return VisitChildren(context); }
89+
7990
/// <summary>
8091
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.statementKeyword"/>.
8192
/// <para>
@@ -197,6 +208,28 @@ public partial class VBAConditionalCompilationParserBaseVisitor<Result> : Abstra
197208
/// <return>The visitor result.</return>
198209
public virtual Result VisitForeignIdentifier([NotNull] VBAConditionalCompilationParser.ForeignIdentifierContext context) { return VisitChildren(context); }
199210

211+
/// <summary>
212+
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.hashElse"/>.
213+
/// <para>
214+
/// The default implementation returns the result of calling <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
215+
/// on <paramref name="context"/>.
216+
/// </para>
217+
/// </summary>
218+
/// <param name="context">The parse tree.</param>
219+
/// <return>The visitor result.</return>
220+
public virtual Result VisitHashElse([NotNull] VBAConditionalCompilationParser.HashElseContext context) { return VisitChildren(context); }
221+
222+
/// <summary>
223+
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.hashEndIf"/>.
224+
/// <para>
225+
/// The default implementation returns the result of calling <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
226+
/// on <paramref name="context"/>.
227+
/// </para>
228+
/// </summary>
229+
/// <param name="context">The parse tree.</param>
230+
/// <return>The visitor result.</return>
231+
public virtual Result VisitHashEndIf([NotNull] VBAConditionalCompilationParser.HashEndIfContext context) { return VisitChildren(context); }
232+
200233
/// <summary>
201234
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.ccExpression"/>.
202235
/// <para>
@@ -307,6 +340,28 @@ public partial class VBAConditionalCompilationParserBaseVisitor<Result> : Abstra
307340
/// <return>The visitor result.</return>
308341
public virtual Result VisitComment([NotNull] VBAConditionalCompilationParser.CommentContext context) { return VisitChildren(context); }
309342

343+
/// <summary>
344+
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.hashElseIf"/>.
345+
/// <para>
346+
/// The default implementation returns the result of calling <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
347+
/// on <paramref name="context"/>.
348+
/// </para>
349+
/// </summary>
350+
/// <param name="context">The parse tree.</param>
351+
/// <return>The visitor result.</return>
352+
public virtual Result VisitHashElseIf([NotNull] VBAConditionalCompilationParser.HashElseIfContext context) { return VisitChildren(context); }
353+
354+
/// <summary>
355+
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.physicalLine"/>.
356+
/// <para>
357+
/// The default implementation returns the result of calling <see cref="AbstractParseTreeVisitor{Result}.VisitChildren(IRuleNode)"/>
358+
/// on <paramref name="context"/>.
359+
/// </para>
360+
/// </summary>
361+
/// <param name="context">The parse tree.</param>
362+
/// <return>The visitor result.</return>
363+
public virtual Result VisitPhysicalLine([NotNull] VBAConditionalCompilationParser.PhysicalLineContext context) { return VisitChildren(context); }
364+
310365
/// <summary>
311366
/// Visit a parse tree produced by <see cref="VBAConditionalCompilationParser.ccConst"/>.
312367
/// <para>

0 commit comments

Comments
 (0)