BaseTools/VfrCompile: Add #pragma once support

The C preprocessor turns each .vfr file into a pre-processed .i
file. At this step, the C preprocessor processes `#pragma once`.
Then, VfrCompile is called (with `-n` to prevent preprocessing)
to parse the pre-processed .i files.

The .i files may still contain `#pragma once` lines. Currently,
VfrCompile treats `once` as an unknown token, causing parse failures.

Originally, this change was going to add a `PragmaOnce` token rule
to the VFR lexer grammar (in VfrSyntax.g) that matched `#pragma once`
lines and silently skipped them using `skip()` and `newline()`. The
`newline()` call would keep line numbers stable for error reporting.
This was consistent with how other preprocessor artifacts were already
handled like `#line` directives (`LineDefinition` and
`GccLineDefinition` tokens) and `extern` declarations (skipped with
`mode(CPP_COMMENT)`).

Writing a regular expression to match `#pragma once` was simple
enough, but it makes overall pragma token recognition more fragile
at the lexer level. When the lexer is walking the DFA state table,
it could begin to match a `#pragma ` line but then not be able to
match remaining characters to recognize tokens other than `once`.

Instead, this change handles `#pragma once` lines in the VFR parser
grammar in `vfrPragmaDefinition` alongside where `pack` is already
handled.

Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
This commit is contained in:
Michael Kubacki 2026-02-03 08:11:53 -05:00 committed by mergify[bot]
parent b963cb6244
commit 3f81a4902a

View file

@ -267,7 +267,7 @@ vfrProgram > [UINT8 Return] :
mConstantOnlyInExpression = FALSE;
>>
(
vfrPragmaPackDefinition
vfrPragmaDefinition
| vfrDataStructDefinition
| vfrDataUnionDefinition
)*
@ -308,14 +308,18 @@ pragmaPackNumber :
<< gCVfrVarDataTypeDB.Pack (LineNum, VFR_PACK_ASSIGN, NULL, PackNumber); >>
;
vfrPragmaPackDefinition :
"\#pragma" "pack" "\("
{
pragmaPackShowDef
| pragmaPackStackDef
| pragmaPackNumber
}
"\)"
vfrPragmaDefinition :
"\#pragma"
(
"pack" "\("
{
pragmaPackShowDef
| pragmaPackStackDef
| pragmaPackNumber
}
"\)"
| "once" // Skip '#pragma once' in preprocessed output
)
;
vfrDataUnionDefinition :