audk/Tools/CCode/Source/VfrCompile/VfrCompile.g

3530 lines
114 KiB
Plaintext

/*++
Copyright (c) 2004 - 2005, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
VfrCompile.g
Abstract:
PCCTS parser and lexer definitions for the EFI VFR forms compiler
--*/
#header<<
#include <Common/UefiBaseTypes.h>
#include <Common/MultiPhase.h>
#include <Common/InternalFormRepresentation.h>
#include <Protocol/UgaDraw.h>
#include <Protocol/Hii.h>
#include "CommonLib.h"
#include "EfiUtilityMsgs.h"
#include "EfiVfr.h"
#include "VfrServices.h"
#include <ctype.h>
#ifndef __GNUC__
#include <direct.h>
#include <process.h> // for spawn functions
#else
#include <unistd.h>
#endif
>>
<<
//
// Base info for DLG-generated scanner
//
#include "DLexerBase.h"
//
// Include the scanner file generated by DLG
//
#include "DLGLexer.h"
class DLGLexerVfr : public DLGLexer
{
public:
DLGLexerVfr (DLGFileInput *F) : DLGLexer (F) {};
INT32 errstd (char *Text)
{
printf ("unrecognized input '%s'\n", Text);
}
};
//
// Base token definitions for ANTLR
//
#include "AToken.h"
//
// This is how we invoke the C preprocessor on the VFR source file
// to resolve #defines, #includes, etc. To make C source files
// shareable between VFR and drivers, define VFRCOMPILE so that
// #ifdefs can be used in shared .h files.
//
#ifdef __GNUC__
#define PREPROCESSOR_COMMAND "gcc "
#define PREPROCESSOR_OPTIONS "-x c -E -P -DVFRCOMPILE "
#define FILE_SEP_CHAR '/'
#define FILE_SEP_STRING "/"
#else
#define PREPROCESSOR_COMMAND "cl.exe "
#define PREPROCESSOR_OPTIONS "/nologo /P /TC /DVFRCOMPILE "
#define FILE_SEP_CHAR '/'
#define FILE_SEP_STRING "/"
#endif
typedef ANTLRCommonToken ANTLRToken;
//
// Specify the filename extensions for the files we generate.
//
#define VFR_BINARY_FILENAME_EXTENSION ".c"
#define VFR_LIST_FILENAME_EXTENSION ".lst"
static
VOID
Usage ();
static
STATUS
ProcessArgs (
int Argc,
char *Argv[]
);
static
VOID
Cleanup ();
//
// Globals
//
OPTIONS gOptions;
int
main (
int argc,
char **argv
)
/*++
Routine Description:
Application entry point function. Parse command-line arguments,
invoke the parser, clean up, and return.
Arguments:
argc - standard argc passed to main() per C conventions
argv - standard argv passed to main() per C conventions
Returns:
STATUS_SUCCESS - program executed with no errors or warnings
STATUS_WARNING - program executed with warnings
STATUS_ERROR - non-recoverable errors encountered while processing
--*/
{
FILE *VfrFptr;
char *Cmd;
char *Cptr;
int Len;
STATUS Status;
//
// Set our program name for the error printing routines.
// Then set printing limits.
//
SetUtilityName (PROGRAM_NAME);
SetPrintLimits (20, 20, 30);
//
// Process the command-line arguments
//
if (ProcessArgs (argc, argv) != STATUS_SUCCESS) {
Usage ();
Cleanup();
return STATUS_ERROR;
}
VfrFptr = NULL;
//
// Verify the VFR script file exists
//
if ((VfrFptr = fopen (gOptions.VfrFileName, "r")) == NULL) {
Error (PROGRAM_NAME, 0, 0, gOptions.VfrFileName, "could not open input VFR file");
Cleanup();
return STATUS_ERROR;
}
//
// Now close the file and make a system call to run the preprocessor
// on it.
//
fclose (VfrFptr);
Len = strlen (PREPROCESSOR_OPTIONS) + strlen (gOptions.VfrFileName) + 10;
if (gOptions.CPreprocessorOptions != NULL) {
Len += strlen (gOptions.CPreprocessorOptions) + 1;
}
if (gOptions.IncludePaths != NULL) {
Len += strlen (gOptions.IncludePaths) + 1;
}
Cmd = (char *)malloc (Len);
if (Cmd == NULL) {
Error (PROGRAM_NAME, 0, 0, NULL, "could not allocate memory");
Cleanup();
return STATUS_ERROR;
}
strcpy (Cmd, PREPROCESSOR_OPTIONS);
if (gOptions.IncludePaths != NULL) {
strcat (Cmd, gOptions.IncludePaths);
strcat (Cmd, " ");
}
if (gOptions.CPreprocessorOptions != NULL) {
strcat (Cmd, gOptions.CPreprocessorOptions);
strcat (Cmd, " ");
}
strcat (Cmd, gOptions.VfrFileName);
#ifndef __GNUC__
Status = _spawnlp (_P_WAIT, PREPROCESSOR_COMMAND, Cmd, NULL);
#else
{
char CommandLine[1000];
char *p;
//
// Lean the slashes forward.
//
for (p = gOptions.PreprocessorOutputFileName; *p; p++) {
if (*p=='\\') {
*p=FILE_SEP_CHAR;
}
}
//
// Lean the slashes forward.
//
for (p = Cmd; *p; p++) {
if (*p=='\\') {
*p=FILE_SEP_CHAR;
}
}
sprintf(CommandLine, "%s %s > %s", PREPROCESSOR_COMMAND, Cmd, gOptions.PreprocessorOutputFileName);
Status = system (CommandLine);
}
#endif
if (Status != 0) {
Error (PROGRAM_NAME, 0, 0, gOptions.VfrFileName, "failed to spawn C preprocessor on VFR file");
printf ("Command: '%s %s'\n", PREPROCESSOR_COMMAND, Cmd);
Cleanup();
return STATUS_ERROR;
}
free (Cmd);
//
// Open the preprocessor output file
//
if ((VfrFptr = fopen (gOptions.PreprocessorOutputFileName, "r")) == NULL) {
Error (PROGRAM_NAME, 0, 0, "failed to open input VFR preprocessor output file",
gOptions.PreprocessorOutputFileName);
Cleanup();
return STATUS_ERROR;
}
//
// Define input VFR file
//
DLGFileInput InputFile (VfrFptr);
//
// Define an instance of the scanner
//
DLGLexerVfr Scanner (&InputFile);
//
// Define token buffer between scanner and parser
//
ANTLRTokenBuffer Pipe (&Scanner);
//
// Create a token to use as a model
//
ANTLRToken Tok;
//
// Tell the scanner what type the token is
//
Scanner.setToken (&Tok);
//
// Create an instance of our parser
//
EfiVfrParser Parser (&Pipe);
//
// Initialize the parser
//
Parser.init ();
Status = GetUtilityStatus ();
if (Status != STATUS_SUCCESS) {
Cleanup();
return Status;
}
//
// Start the first rule
//
Parser.program ();
//
// Close the input script file
//
fclose (VfrFptr);
Parser.WriteIfrBytes ();
//
// Call cleanup, which does some extra checking of the script
//
Parser.Cleanup ();
Cleanup();
//
// If we had an error somewhere, delete our output files so that
// a subsequent build will rebuild them.
//
Status = GetUtilityStatus ();
if (Status == STATUS_ERROR) {
remove (gOptions.IfrOutputFileName);
}
return Status;
}
static
VOID
Cleanup ()
/*++
Routine Description:
Free up memory allocated during parsing.
Arguments:
None
Returns:
None
--*/
{
//
// Free up our string we allocated to track the include paths
//
if (gOptions.IncludePaths != NULL) {
free (gOptions.IncludePaths);
gOptions.IncludePaths = NULL;
}
//
// Free up our string we allocated to track preprocessor options
//
if (gOptions.CPreprocessorOptions != NULL) {
free (gOptions.CPreprocessorOptions);
gOptions.CPreprocessorOptions = NULL;
}
}
static
STATUS
ProcessArgs (
int Argc,
char *Argv[]
)
/*++
Routine Description:
Process the command-line arguments.
Arguments:
Argc - standard argc passed to main()
Argv - standard argv passed to main()
Returns:
STATUS_SUCCESS - program should continue (all args ok)
--*/
{
char *IncludePaths;
char *CPreprocessorOptions;
int Len;
char CopyStr[MAX_PATH];
char *Cptr;
//
// Put options in known state.
//
memset ((char *)&gOptions, 0, sizeof (OPTIONS));
//
// Go through all the arguments that start with '-'
//
Argc--;
Argv++;
while ((Argc > 0) && (Argv[0][0] == '-')) {
//
// -? or -h help option -- return an error for printing usage
//
if ((stricmp (Argv[0], "-?") == 0) || (stricmp (Argv[0], "-h") == 0)) {
return STATUS_ERROR;
break;
//
// -l to create a listing output file
//
} else if (stricmp (Argv[0], "-l") == 0) {
gOptions.CreateListFile = 1;
//
// -I include_path option for finding include files. We'll pass this
// to the preprocessor. Turn them all into a single include string.
//
} else if (stricmp (Argv[0], "-i") == 0) {
if ((Argc < 2) || (Argv[1][0] == '-')) {
Error (PROGRAM_NAME, 0, 0, Argv[0], "missing path argument");
return STATUS_ERROR;
}
Argc--;
Argv++;
Len = strlen (" -I ");
Len += strlen (Argv[0]) + 2;
if (gOptions.IncludePaths != NULL) {
Len += strlen (gOptions.IncludePaths);
}
IncludePaths = (CHAR8 *)malloc (Len);
if (IncludePaths == NULL) {
Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");
return STATUS_ERROR;
}
IncludePaths[0] = 0;
if (gOptions.IncludePaths != NULL) {
strcpy (IncludePaths, gOptions.IncludePaths);
free (gOptions.IncludePaths);
}
strcat (IncludePaths, " -I ");
strcat (IncludePaths, Argv[0]);
gOptions.IncludePaths = IncludePaths;
//
// -od OutputDirectory to define a common directory for output files
//
} else if (stricmp (Argv[0], "-od") == 0) {
if ((Argc < 2) || (Argv[1][0] == '-')) {
Error (PROGRAM_NAME, 0, 0, Argv[0], "missing output directory name");
return STATUS_ERROR;
}
Argc--;
Argv++;
strcpy (gOptions.OutputDirectory, Argv[0]);
} else if (stricmp (Argv[0], "-ibin") == 0) {
gOptions.CreateIfrBinFile = 1;
} else if (stricmp (Argv[0], "-nostrings") == 0) {
// deprecated option
//
// -ppflag C-preprocessor-flag option for passing options to the C preprocessor.
// Turn them all into a single string.
//
} else if (stricmp (Argv[0], "-ppflag") == 0) {
if (Argc < 2) {
Error (PROGRAM_NAME, 0, 0, Argv[0], "missing C-preprocessor argument");
return STATUS_ERROR;
}
Argc--;
Argv++;
Len = strlen (Argv[0]) + 2;
if (gOptions.CPreprocessorOptions != NULL) {
Len += strlen (gOptions.CPreprocessorOptions);
}
CPreprocessorOptions = (CHAR8 *)malloc (Len);
if (CPreprocessorOptions == NULL) {
Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");
return STATUS_ERROR;
}
CPreprocessorOptions[0] = 0;
if (gOptions.CPreprocessorOptions != NULL) {
strcpy (CPreprocessorOptions, gOptions.CPreprocessorOptions);
free (gOptions.CPreprocessorOptions);
}
strcat (CPreprocessorOptions, " ");
strcat (CPreprocessorOptions, Argv[0]);
gOptions.CPreprocessorOptions = CPreprocessorOptions;
} else {
Error (PROGRAM_NAME, 0, 0, Argv[0], "unrecognized option");
return STATUS_ERROR;
}
Argc--;
Argv++;
}
//
// Must specify at least the vfr file name
//
if (Argc > 1) {
Error (PROGRAM_NAME, 0, 0, Argv[1], "unrecognized argument after VFR file name");
return STATUS_ERROR;
} else if (Argc < 1) {
Error (PROGRAM_NAME, 0, 0, NULL, "must specify VFR file name");
return STATUS_ERROR;
}
strcpy (gOptions.VfrFileName, Argv[0]);
//
// We run the preprocessor on the VFR file to manage #include statements.
// Unfortunately the preprocessor does not allow you to specify the
// output name or path of the resultant .i file, so we have to do
// some work. Here we'll extract the basename of the VFR file, then
// append .i on the end.
//
strcpy (CopyStr, gOptions.VfrFileName);
Cptr = CopyStr + strlen (CopyStr) - 1;
for (;(Cptr > CopyStr) && (*Cptr != '\\') && (*Cptr != ':') && (*Cptr != '/'); Cptr--);
if (Cptr == CopyStr) {
strcpy (gOptions.PreprocessorOutputFileName, Cptr);
strcpy (gOptions.VfrBaseFileName, Cptr);
} else {
strcpy (gOptions.PreprocessorOutputFileName, Cptr+1);
strcpy (gOptions.VfrBaseFileName, Cptr+1);
}
for (Cptr = gOptions.PreprocessorOutputFileName; *Cptr && (*Cptr != '.'); Cptr++);
strcpy (Cptr, ".i");
//
// Terminate the vfr file basename at the extension
//
for (Cptr = gOptions.VfrBaseFileName; *Cptr && (*Cptr != '.'); Cptr++) {
}
*Cptr = 0;
//
// If they defined an output directory, prepend all output files
// with the working directory. Output files of interest:
// VfrListFileName -- list file
// IfrOutputFileName -- IFR bytes
// StringOutputFileName -- string bytes
// StringListFileName -- not used
// StringDefineFileName -- #defines of string identifiers
//
// We have two cases:
// 1. Output directory (-od) not specified, in which case output files
// go to the current working directory.
// 2. Output directory specified, in which case the output files
// go directly to the specified directory.
//
if (gOptions.OutputDirectory[0] == 0) {
CopyStr[0] = 0;
#ifndef __GNUC__
_getcwd (CopyStr, sizeof (CopyStr));
#else
getcwd (CopyStr, sizeof (CopyStr));
#endif
strcpy (gOptions.OutputDirectory, CopyStr);
}
//
// Make sure output directory has a trailing backslash
//
if (gOptions.OutputDirectory[strlen (gOptions.OutputDirectory) - 1] != '\\' ||
gOptions.OutputDirectory[strlen (gOptions.OutputDirectory) - 1] != '/') {
strcat (gOptions.OutputDirectory, FILE_SEP_STRING);
}
//
// Create the base output file name as: path\base, copy it to all the output
// filenames, and then add the appropriate extension to each.
//
strcpy (gOptions.VfrListFileName, gOptions.OutputDirectory);
strcat (gOptions.VfrListFileName, gOptions.VfrBaseFileName);
strcpy (gOptions.IfrOutputFileName, gOptions.VfrListFileName);
strcat (gOptions.VfrListFileName, VFR_LIST_FILENAME_EXTENSION);
strcat (gOptions.IfrOutputFileName, VFR_BINARY_FILENAME_EXTENSION);
//
// We set a default list file name, so if they do not
// want a list file, null out the name now.
//
if (gOptions.CreateListFile == 0) {
gOptions.VfrListFileName[0] = 0;
}
return STATUS_SUCCESS;
}
static
VOID
Usage ()
/*++
Routine Description:
Print utility usage instructions
Arguments:
None
Returns:
None
--*/
{
int Index;
const char *Help[] = {
" ",
"VfrCompile version " VFR_COMPILER_VERSION,
" ",
" Usage: VfrCompile {options} [VfrFile]",
" ",
" where options include:",
" -? or -h prints this help",
" -l create an output IFR listing file",
" -i IncPath add IncPath to the search path for VFR included files",
" -od OutputDir deposit all output files to directory OutputDir (default=cwd)",
" -ibin create an IFR HII pack file",
" where parameters include:",
" VfrFile name of the input VFR script file",
" ",
NULL
};
for (Index = 0; Help[Index] != NULL; Index++) {
fprintf (stdout, "%s\n", Help[Index]);
}
}
>>
#lexaction
<<
#include "EfiVfr.h"
PARSER_LINE_DEFINITION *gLineDefinition = NULL;
PARSER_LINE_DEFINITION *gLastLineDefinition = NULL;
VOID
AddFileLine (
char *TokenString,
UINT32 TokenLine
)
/*++
Routine Description:
During the lexer phase, if we encounter a #line statement output by
the preprocessor, this function gets called. We'll save off the info
for error reporting purposes. The preprocessor line information has the
form:
#line 3 "FileName.c"
Arguments:
TokenString - the parsed string as shown above
TokenLine - the line number in the preprocessed output file
Returns:
NA
--*/
{
PARSER_LINE_DEFINITION *LineDef;
CHAR8 *Cptr;
//
// Allocate a structure in which we can keep track of this line information.
//
LineDef = (PARSER_LINE_DEFINITION *)malloc (sizeof (PARSER_LINE_DEFINITION));
memset ((char *)LineDef, 0, sizeof (PARSER_LINE_DEFINITION));
LineDef->TokenLineNum = TokenLine;
LineDef->HashLineNum = atoi (TokenString + 6);
//
// Find the quotes in the filename, then allocate space in the line
// def structure for a copy of the filename. Finally, copy it without
// quotes to the line def.
//
for (Cptr = TokenString + 7; *Cptr && (*Cptr != '"'); Cptr++);
if (*Cptr == '"') {
LineDef->FileName = (CHAR8 *)malloc (strlen (Cptr));
Cptr++;
strcpy (LineDef->FileName, Cptr);
for (Cptr = LineDef->FileName; *Cptr && (*Cptr != '"'); Cptr++);
*Cptr = 0;
//
// Now add this new one to the list
//
if (gLineDefinition == NULL) {
gLineDefinition = LineDef;
} else {
gLastLineDefinition->Next = LineDef;
}
gLastLineDefinition = LineDef;
} else {
Error (PROGRAM_NAME, 0, 0, "invalid line definition in preprocessor output file", TokenString);
free (LineDef);
return;
}
}
char *
ConvertLineNumber (
UINT32 *LineNum
)
/*++
Routine Description:
Given the line number in the preprocessor-output file, use the line number
information we've saved to determine the source file name and line number
where the code originally came from. This is required for error reporting.
Arguments:
LineNum - the line number in the preprocessor-output file.
Returns:
Returns a pointer to the source file name. Also returns the line number
in the provided LineNum argument
--*/
{
PARSER_LINE_DEFINITION *LineDef;
//
// Step through our linked list of #line information we saved off.
// For each one, look at its line number, and the line number of the
// next record, and see if the passed-in line number is in the range.
// If it is, then convert the line number to the appropriate line number
// of the original source file.
//
for (LineDef = gLineDefinition; LineDef != NULL; LineDef = LineDef->Next) {
//
// The given LineNum is the line number from the .i file.
// Find a line definition whose range includes this line number,
// convert the line number, and return the filename.
//
if (LineDef->TokenLineNum <= *LineNum) {
if (LineDef->Next != NULL) {
if (LineDef->Next->TokenLineNum > *LineNum) {
*LineNum = *LineNum - LineDef->TokenLineNum + LineDef->HashLineNum;
return LineDef->FileName;
}
} else {
//
// Last one in the list of line definitions, so has to be right
//
*LineNum = *LineNum - LineDef->TokenLineNum + LineDef->HashLineNum;
return LineDef->FileName;
}
}
}
return NULL;
}
>>
//
// Define a lexical class for parsing quoted strings. Basically
// starts with a double quote, and ends with a double quote that
// is not preceeded with a backslash.
//
#lexclass QUOTED_STRING
#token TheString "~[\"]*\"" << mode (START); >>
//
// Define a lexical class for parsing "#pragma pack" statements.
// We do this just for convenience (since we skip them here) so
// that users can include some minimal .h files.
//
#lexclass PRAGMA_PACK
#token "pack" << skip (); >>
#token "[\ \t]" << skip (); >>
#token "\(" << skip (); >>
#token "[0-9]*" << skip (); >>
#token "\)" << skip (); mode (START); >>
//
// Define a lexclass for skipping over C++ style comments
//
#lexclass CPP_COMMENT
#token "~[\n]*" << skip (); >>
#token "\n" << skip (); mode (START); newline (); >>
//
// Standard lexclass is START
//
#lexclass START
//
// Find start of C++ style comments
//
#token "//" << skip (); mode (CPP_COMMENT); >>
//
// Skip whitespace
//
#token "[\ \t]" << skip (); >>
//
// Skip over newlines, but count them
//
#token "\n" << skip (); newline (); >>
//
// Skip pragma pack statements
//
#token "\#pragma" << skip (); mode(PRAGMA_PACK); >>
//
// Skip over 'extern' in any included .H file
//
#token "extern" << skip (); >>
//
// Tokens for the different keywords. Syntax is:
// TokenName("ErrorMessageText") "TokenString"
// where:
// TokenName is the token name (must be capitalized) that is used in the rules
// ErrorMessageText is the string the compiler emits when it detects a syntax error
// TokenString is the actual matching string used in the user script
//
#token LineDefinition "#line\ [0-9]+\ \"~[\"]+\"[\ \t]*\n" << AddFileLine (begexpr (), line ()); skip (); >>
#token FormSet("formset") "formset"
#token EndFormSet("endformset") "endformset"
#token Title("title") "title"
#token FormId("formid") "formid"
#token OneOf("oneof") "oneof"
#token Prompt("prompt") "prompt"
#token OrderedList("orderedlist") "orderedlist"
#token EndList("endlist") "endlist"
#token EndForm("endform") "endform"
#token EndOneOf("endoneof") "endoneof"
#token Form("form") "form"
#token Subtitle("subtitle") "subtitle"
#token Help("help") "help"
#token VarId("varid") "varid"
#token Text("text") "text"
#token Option("option") "option"
#token Value("value") "value"
#token Flags("flags") "flags"
#token Date("date") "date"
#token EndDate("enddate") "enddate"
#token Year("year") "year"
#token Month("month") "month"
#token Day("day") "day"
#token Time("time") "time"
#token EndTime("endtime") "endtime"
#token Hour("hour") "hour"
#token Minute("minute") "minute"
#token Second("second") "second"
#token AND("AND") "AND"
#token OR("OR") "OR"
#token GrayOutIf("grayoutif") "grayoutif"
#token NOT("NOT") "NOT"
#token Label("label") "label"
#token Timeout("timeout") "timeout"
#token Inventory("inventory") "inventory"
#token StringToken("STRING_TOKEN") "STRING_TOKEN"
#token NonNvDataMap("_NON_NV_DATA_MAP") "_NON_NV_DATA_MAP"
#token Struct("struct") "struct"
#token Uint64("UINT64") "UINT64"
#token Uint32("UINT32") "UINT32"
#token Uint16("UINT16") "UINT16"
#token Char16("CHAR16") "CHAR16"
#token Uint8("UINT8") "UINT8"
#token Guid("guid") "guid"
#token CheckBox("checkbox") "checkbox"
#token EndCheckBox("endcheckbox") "endcheckbox"
#token Numeric("numeric") "numeric"
#token EndNumeric("endnumeric") "endnumeric"
#token Minimum("minimum") "minimum"
#token Maximum("maximum") "maximum"
#token Step("step") "step"
#token Default("default") "default"
#token Password("password") "password"
#token EndPassword("endpassword") "endpassword"
#token String("string") "string"
#token EndString("endstring") "endstring"
#token MinSize("minsize") "minsize"
#token MaxSize("maxsize") "maxsize"
#token Encoding("encoding") "encoding"
#token SuppressIf("suppressif") "suppressif"
#token Hidden("hidden") "hidden"
#token Goto("goto") "goto"
#token InconsistentIf "inconsistentif"
#token EndIf("endif") "endif"
#token IdEqId("ideqid") "ideqid"
#token IdEqVal("ideqval") "ideqval"
#token VarEqVal("vareqval") "vareqval"
#token Var("var") "var"
#token IdEqValList("ideqvallist") "ideqvallist"
#token Length("length") "length"
#token Values("values") "values"
#token Key("key") "key"
#token DefaultFlag("DEFAULT") "DEFAULT"
#token ManufacturingFlag("MANUFACTURING") "MANUFACTURING"
#token InteractiveFlag("INTERACTIVE") "INTERACTIVE"
#token NVAccessFlag("NV_ACCESS") "NV_ACCESS"
#token ResetRequiredFlag("RESET_REQUIRED") "RESET_REQUIRED"
#token LateCheckFlag("LATE_CHECK") "LATE_CHECK"
#token Class("class") "class"
#token Subclass("subclass") "subclass"
#token TypeDef("typedef") "typedef"
#token Restore("restore") "restore"
#token Save("save") "save"
#token Defaults("defaults") "defaults"
#token Banner("banner") "banner"
#token Align("align") "align"
#token Left("left") "left"
#token Right("right") "right"
#token Center("center") "center"
#token Line("line") "line"
#token VarStore("varstore") "varstore"
#token Name("name") "name"
#token Oem("oem") "oem"
#token True("TRUE") "TRUE"
#token False("FALSE") "FALSE"
#token GreaterThan(">") ">"
#token GreaterEqual(">=") ">="
#token LessThan("<") "<"
#token LessEqual("<=") "<="
//
// Define the class and subclass tokens
//
#token ClassNonDevice("NONDEVICE") "NON_DEVICE"
#token ClassDiskDevice("DISK_DEVICE") "DISK_DEVICE"
#token ClassVideoDevice("VIDEO_DEVICE") "VIDEO_DEVICE"
#token ClassNetworkDevice("NETWORK_DEVICE") "NETWORK_DEVICE"
#token ClassInputDevice("INPUT_DEVICE") "INPUT_DEVICE"
#token ClassOnBoardDevice("ONBOARD_DEVICE") "ONBOARD_DEVICE"
#token ClassOtherDevice("OTHER_DEVICE") "OTHER_DEVICE"
#token SubclassSetupApplication("SETUP_APPLICATION") "SETUP_APPLICATION"
#token SubclassGeneralApplication("GENERAL_APPLICATION") "GENERAL_APPLICATION"
#token SubclassFrontPage("FRONT_PAGE") "FRONT_PAGE"
#token SubclassSingleUse("SINGLE_USE") "SINGLE_USE"
#token LanguageIdentifier("language identifier") "[a-z][a-z][a-z]" // 3 lowercase characters
#token StringIdentifier("string identifier") "[A-Za-z_][A-Za-z_0-9]*"
#token Number("numeric value") "(0x[0-9A-Fa-f]+) | [0-9]+"
#token OpenBrace("{") "\{"
#token CloseBrace("}") "\}"
#token OpenParen("(") "\("
#token CloseParen(")") "\)"
#token OpenBracket("[") "\["
#token CloseBracket("]") "\]"
//
// Define all other invalid characters so that they get through the lexical phase
// and we can catch them during the parse phase. We get much better error
// messages then.
//
#token InvalidCharacters("invalid characters") "~[;:=,\.\|]"
//
// This is the overall definition of a VFR form definition script.
//
program :
( dataStructDefinition )*
formSetStatement
( vfrStatementVarStore )*
( formDefinition )*
EFS:EndFormSet ";" << WriteOpByte (EFS->getLine(), EFI_IFR_END_FORM_SET_OP); >>
"@" // end of file
;
formSetStatement :
FS:FormSet << WriteOpByte (FS->getLine(), EFI_IFR_FORM_SET_OP); >>
Guid "="
OpenBrace
G1:Number ","
G2:Number ","
G3:Number ","
OpenBrace
G4:Number ","
G5:Number ","
G6:Number ","
G7:Number ","
G8:Number ","
G9:Number ","
G10:Number ","
G11:Number
CloseBrace
CloseBrace << WriteGuidValue (G1->getLine (), G1->getText (), G2->getText (), G3->getText (),
G4->getText (), G5->getText (), G6->getText (), G7->getText (),
G8->getText (), G9->getText (), G10->getText (), G11->getText ()
);
>>
","
Title "=" getStringId ","
Help "=" getStringId ","
//
// insert padding for an EFI_PHYSICAL_ADDRESS (UINT64)
//
<< WriteDWord (0, 0); WriteDWord (0, 0); >>
Class "=" CVAL:classDefinition "," << WriteClass (); >>
Subclass "=" SVAL:subclassDefinition "," << WriteSubclass (); >>
<< WriteWord (mNvDataStructSize); >>
;
//
// A form can be of multiple classes, thus allow CLASS_A | CLASS_B | CLASS_C
//
classDefinition :
validClassNames ( "\|" validClassNames )*
;
validClassNames :
CND:ClassNonDevice << SetClass (CND->getLine(), EFI_NON_DEVICE_CLASS); >>
| CDD:ClassDiskDevice << SetClass (CDD->getLine(), EFI_DISK_DEVICE_CLASS); >>
| CVD:ClassVideoDevice << SetClass (CVD->getLine(), EFI_VIDEO_DEVICE_CLASS); >>
| CNW:ClassNetworkDevice << SetClass (CNW->getLine(), EFI_NETWORK_DEVICE_CLASS); >>
| CID:ClassInputDevice << SetClass (CID->getLine(), EFI_INPUT_DEVICE_CLASS); >>
| COB:ClassOnBoardDevice << SetClass (COB->getLine(), EFI_ON_BOARD_DEVICE_CLASS); >>
| COD:ClassOtherDevice << SetClass (COD->getLine(), EFI_OTHER_DEVICE_CLASS); >>
| CNUM:Number << SetClass (CNUM->getLine(), GetNumber (CNUM->getText(), CNUM->getLine(), 4)); >>
; << PrintErrorMessage (LT(1)->getLine(), LT(1)->getText(), "invalid class"); >>
//
// A form can only be of one subclass type.
//
subclassDefinition :
SSA:SubclassSetupApplication << SetSubclass (SSA->getLine(), EFI_SETUP_APPLICATION_SUBCLASS); >>
| SGA:SubclassGeneralApplication << SetSubclass (SGA->getLine(), EFI_GENERAL_APPLICATION_SUBCLASS); >>
| SFP:SubclassFrontPage << SetSubclass (SFP->getLine(), EFI_FRONT_PAGE_SUBCLASS); >>
| SSU:SubclassSingleUse << SetSubclass (SSU->getLine(), EFI_SINGLE_USE_SUBCLASS); >>
| SNUM:Number << SetSubclass (SNUM->getLine(), GetNumber (SNUM->getText(), SNUM->getLine(), 4)); >>
; << PrintErrorMessage (LT(1)->getLine(), LT(1)->getText(), "invalid subclass"); >>
//
// Parse a C type data structure for storing VFR setup data. Allow:
// typedef struct _XXX_ {
// (fields)
// } MY_NV_DATA;
//
dataStructDefinition :
<< int IsNonNV = 0; >>
{ TypeDef }
S:Struct
(
NonNvDataMap << IsNonNV = 1; >>
|
{ StringIdentifier }
) << StartStructDefinition (IsNonNV, S->getLine()); >>
OpenBrace
dataStructFields
CloseBrace NAME:StringIdentifier << EndStructDefinition (NAME->getText(), NAME->getLine()); >>
";"
;
//
// Parse a C type data structure for defining data that is not stored in NV.
// typedef struct _NON_NV_DATA_MAP {
// (fields)
// } NON_NV_DATA_MAP;
//
nonNvDataStructDefinition :
{ TypeDef }
Struct NonNvDataMap
{ StringIdentifier }
OpenBrace
dataStructFields
CloseBrace NAME:StringIdentifier << AddStructField (NAME->getText(), NAME->getLine(), 0, 0, 0); >>
";"
;
dataStructFields :
( dataStructField64 | dataStructField32 | dataStructField16 | dataStructField8 ) *
;
//*****************************************************************************
//
// PARSE:
// UINT64 Name[4];
// UINT64 Name;
//
// Used while parsing the NV data map structures.
//
dataStructField64 :
<< int ArrayLength = 1; char IsArray = 0; >>
"UINT64"
NAME:StringIdentifier
( ";" | OpenBracket IVal:Number CloseBracket ";" << ArrayLength = GetNumber (IVal->getText(), IVal->getLine(), 4); IsArray = 1; >> )
<< AddStructField (NAME->getText(), NAME->getLine(), 8, ArrayLength, IsArray); >>
;
//*****************************************************************************
//
// PARSE:
// UINT32 Name[4];
// UINT32 Name;
//
// Used while parsing the NV data map structures.
//
dataStructField32 :
<< int ArrayLength = 1; char IsArray = 0; >>
"UINT32"
NAME:StringIdentifier
( ";" | OpenBracket IVal:Number CloseBracket ";" << ArrayLength = GetNumber (IVal->getText(), IVal->getLine(), 4); IsArray = 1; >> )
<< AddStructField (NAME->getText(), NAME->getLine(), 4, ArrayLength, IsArray); >>
;
//*****************************************************************************
//
// PARSE:
// UINT16 Name[4];
// UINT16 Name;
//
// Used while parsing the NV data map structures.
//
dataStructField16 :
<< int ArrayLength = 1; char IsArray = 0; >>
( "UINT16" | "CHAR16" )
NAME:StringIdentifier
( ";" | OpenBracket IVal:Number CloseBracket ";" << ArrayLength = GetNumber (IVal->getText(), IVal->getLine(), 4); IsArray = 1; >> )
<< AddStructField (NAME->getText(), NAME->getLine(), 2, ArrayLength, IsArray); >>
;
//*****************************************************************************
//
// PARSE:
// UINT8 Name[4];
// UINT8 Name;
//
// Used while parsing the NV data map structures.
//
dataStructField8 :
<< int ArrayLength = 1; char IsArray = 0; >>
"UINT8"
NAME:StringIdentifier
( ";" | OpenBracket IVal:Number CloseBracket ";" << ArrayLength = GetNumber (IVal->getText(), IVal->getLine(), 4); IsArray = 1; >> )
<< AddStructField (NAME->getText(), NAME->getLine(), 1, ArrayLength, IsArray); >>
;
//*****************************************************************************
//
// PARSE:
// form formid = 1,
// title = STRING_TOKEN(STR_FORM_TITLE);
// -- form statements --
// endform;
//
// The Form ID cannot be 0
//
formDefinition :
FRM:Form FormId << WriteOpByte (FRM->getLine(), EFI_IFR_FORM_OP); >>
"="
VAL:Number << WriteWord (GetNumber (VAL->getText(), VAL->getLine(), 2)); AddFormId (GetNumber (VAL->getText(), VAL->getLine(), 2), VAL->getLine()); >>
","
Title "=" getStringId ";" // writes string identifier
( vfrStatements )*
ENDF:EndForm ";" << WriteOpByte (ENDF->getLine(), EFI_IFR_END_FORM_OP); >>
;
//
// VFR statements in a formset
//
vfrStatements :
vfrStatementSubTitle |
vfrStatementOneOf |
vfrStatementTextText |
vfrStatementCheckBox |
vfrStatementNumeric |
vfrStatementDate |
vfrStatementTime |
vfrStatementPassword |
vfrStatementString |
vfrStatementSuppressIf |
vfrStatementHidden |
vfrStatementGoto |
vfrStatementGrayOutIf |
vfrStatementInconsistentIf |
vfrStatementLabel |
vfrStatementBanner |
vfrStatementInventory |
vfrStatementOrderedList |
vfrStatementOem |
vfrStatementSaveRestoreDefaults
;
//*****************************************************************************
//
// PARSE:
// label 100;
//
vfrStatementLabel :
OPID:Label << WriteOpByte (OPID->getLine(), EFI_IFR_LABEL_OP); >>
VAL:Number <<
WriteWord (GetNumber (VAL->getText(), VAL->getLine(), 2));
AddLabel (GetNumber (VAL->getText(), VAL->getLine(), 2), VAL->getLine());
>>
";"
;
//*****************************************************************************
//
// PARSE:
// oem 0x12, 0x34, 0x56;
//
vfrStatementOem :
OPID:Oem << WriteOpByte (OPID->getLine(), EFI_IFR_OEM_DEFINED_OP); >>
( VAL1:Number << WriteByte (GetNumber (VAL1->getText(), VAL1->getLine(), 1), 0); >> )
( "," VAL2:Number << WriteByte (GetNumber (VAL2->getText(), VAL2->getLine(), 1), 0); >> )*
";"
;
//*****************************************************************************
//
// PARSE:
// inconsistentif NOT .... AND NOT .... OR ... endif;
//
vfrStatementInconsistentIf :
<< ResetFlags (); >>
IIFOP:InconsistentIf << WriteOpByte (IIFOP->getLine(), EFI_IFR_INCONSISTENT_IF_OP); >>
Prompt "=" getStringId ","
{
FF:Flags "=" flagsField ( "\|" flagsField )* ","
}
<< WriteFlags (); >> // write the flags field
vfrBooleanExpression
EOP:EndIf ";" << WriteOpByte (EOP->getLine(), EFI_IFR_END_IF_OP); >>
;
//*****************************************************************************
//
// PARSE:
// TRUE AND (ideqval SomeStruct.SomeMember >= 0x10 OR
// ideqid SomeStruct.SomeMember < SomeStruct.SomeOtherMember) AND
// (ideqlist SomeStruct.SomeOtherMember == 0x10, 0x20, 0x30 OR
// vareqval var(VAR_EQ_TEST_NAME) == 0x1)
//
// For supporting complex express, divide the vfrBooleanExpression to two parts
// so that pred-LL(k) parser can parse incrementally.
//
vfrBooleanExpression :
leftPartVfrBooleanExp { rightPartVfrBooleanExp }
;
leftPartVfrBooleanExp :
OpenParen vfrBooleanExpression CloseParen |
(ideqval | ideqid | ideqvallist | vareqval | truefalse) |
NOPID:NOT leftPartVfrBooleanExp << WriteOpByte (NOPID->getLine(), EFI_IFR_NOT_OP); >>
;
rightPartVfrBooleanExp :
AOPID:AND vfrBooleanExpression << WriteOpByte (AOPID->getLine(), EFI_IFR_AND_OP); >> |
OOPID:OR vfrBooleanExpression << WriteOpByte (OOPID->getLine(), EFI_IFR_OR_OP); >>
;
//*****************************************************************************
//
// PARSE:
// TRUE
//
truefalse :
TOPID:True << WriteOpByte (TOPID->getLine(), EFI_IFR_TRUE_OP); >> |
FOPID:False << WriteOpByte (FOPID->getLine(), EFI_IFR_FALSE_OP); >>
;
//*****************************************************************************
//
// PARSE:
// varstore MY_STRUCT_NAME, key = 0x1234, name = "MyVariableName", guid = {...};
//
vfrStatementVarStore :
OP:VarStore << WriteOpByte (OP->getLine(), EFI_IFR_VARSTORE_OP); >>
STRUCT_NAME:StringIdentifier ","
Key "=" KNUM:Number ","
Name "=" VAR_NAME:StringIdentifier ","
Guid "="
OpenBrace
G1:Number ","
G2:Number ","
G3:Number ","
OpenBrace
G4:Number ","
G5:Number ","
G6:Number ","
G7:Number ","
G8:Number ","
G9:Number ","
G10:Number ","
G11:Number
CloseBrace
CloseBrace << WriteGuidValue (G1->getLine (), G1->getText (), G2->getText (), G3->getText (),
G4->getText (), G5->getText (), G6->getText (), G7->getText (),
G8->getText (), G9->getText (), G10->getText (), G11->getText ()
);
WriteWord (GetNumber (KNUM->getText(), KNUM->getLine(), 2));
AddVarStore (STRUCT_NAME->getText(), VAR_NAME->getText(), GetNumber (KNUM->getText(), KNUM->getLine(), 2), STRUCT_NAME->getLine());
>>
";"
;
//*****************************************************************************
//
// PARSE:
// vareqval var(0x100) == 0x20
//
vareqval :
OPID:VarEqVal << WriteOpByte (OPID->getLine(), EFI_IFR_EQ_VAR_VAL_OP); >>
Var OpenParen
VAR:Number << WriteWord (GetNumber (VAR->getText(), VAR->getLine(), 2)); >>
CloseParen
compareNumber
;
ideqval :
OPID:IdEqVal << WriteOpByte (OPID->getLine(), EFI_IFR_EQ_ID_VAL_OP); >>
vfrStructFieldName[0]
compareNumber
;
//*****************************************************************************
//
// PARSE:
// ideqid MyNVData3.Field16A == MyNVData3.Field16B
//
// NOTE: Before processing the second variable store in the ideqid statement, set a global flag
// so that when we parse the second variable we set the secondary variable store id.
//
ideqid :
OPID:IdEqId << WriteOpByte (OPID->getLine(), EFI_IFR_EQ_ID_ID_OP); >>
vfrStructFieldName[0]
compareVfrStructFieldNameNL0
;
//*****************************************************************************
//
// compareNumber is the combination of compare operation and Number
//
compareNumber :
(
"=="
VAL1:Number << WriteWord (GetNumber (VAL1->getText(), VAL1->getLine(), 2)); >>
) |
(
GTOPID:GreaterThan
VAL2:Number << WriteWord (GetNumber (VAL2->getText(), VAL2->getLine(), 2));
WriteOpByte (GTOPID->getLine(), EFI_IFR_GT_OP); >>
) |
(
GEOPID:GreaterEqual
VAL3:Number << WriteWord (GetNumber (VAL3->getText(), VAL3->getLine(), 2));
WriteOpByte (GEOPID->getLine(), EFI_IFR_GE_OP); >>
) |
(
LTOPID:LessThan
VAL4:Number << WriteWord (GetNumber (VAL4->getText(), VAL4->getLine(), 2));
WriteOpByte (LTOPID->getLine(), EFI_IFR_GE_OP);
WriteOpByte (LTOPID->getLine(), EFI_IFR_NOT_OP); >>
) |
(
LEOPID:LessEqual
VAL5:Number << WriteWord (GetNumber (VAL5->getText(), VAL5->getLine(), 2));
WriteOpByte (LEOPID->getLine(), EFI_IFR_GT_OP);
WriteOpByte (LEOPID->getLine(), EFI_IFR_NOT_OP); >>
)
;
//*****************************************************************************
//
// compareVfrStructFieldNameNL0 is the combination of compare operation and vfrStructFieldNameNL[0]
//
compareVfrStructFieldNameNL0 :
(
"==" << mIdEqIdStmt = 1; >>
vfrStructFieldNameNL[0] << mIdEqIdStmt = 0; >>
) |
(
GTOPID:GreaterThan << mIdEqIdStmt = 1; >>
vfrStructFieldNameNL[0] << mIdEqIdStmt = 0;
WriteOpByte (GTOPID->getLine(), EFI_IFR_GT_OP); >>
) |
(
GEOPID:GreaterEqual << mIdEqIdStmt = 1; >>
vfrStructFieldNameNL[0] << mIdEqIdStmt = 0;
WriteOpByte (GEOPID->getLine(), EFI_IFR_GE_OP); >>
) |
(
LTOPID:LessThan << mIdEqIdStmt = 1; >>
vfrStructFieldNameNL[0] << mIdEqIdStmt = 0;
WriteOpByte (LTOPID->getLine(), EFI_IFR_GE_OP);
WriteOpByte (LTOPID->getLine(), EFI_IFR_NOT_OP); >>
) |
(
LEOPID:LessEqual << mIdEqIdStmt = 1; >>
vfrStructFieldNameNL[0] << mIdEqIdStmt = 0;
WriteOpByte (LEOPID->getLine(), EFI_IFR_GT_OP);
WriteOpByte (LEOPID->getLine(), EFI_IFR_NOT_OP); >>
)
;
ideqvallist :
OPID:IdEqValList << WriteOpByte (OPID->getLine(), EFI_IFR_EQ_ID_LIST_OP); >>
vfrStructFieldName[0]
"=="
( VAL:Number << QueueIdEqValList (GetNumber (VAL->getText(), VAL->getLine(), 2)); >> ) +
<< FlushQueueIdEqValList(); >>
;
vfrStatementGoto :
<< UINT32 LineNum, KeyValue = 0; ResetFlags (); >>
IDG:Goto << WriteOpByte (IDG->getLine(), EFI_IFR_REF_OP); >>
VAL:Number "," << WriteWord (GetNumber (VAL->getText(), VAL->getLine(), 2));
AddGotoReference (GetNumber (VAL->getText(), VAL->getLine(), 2), VAL->getLine());
>>
KP:Prompt "=" getStringId "," << LineNum = KP->getLine(); >>
Help "=" getStringId
{
","
FF:Flags "=" flagsField ( "\|" flagsField )* << LineNum = FF->getLine(); >>
}
{
"," Key "=" KNUM:Number << LineNum = KNUM->getLine(); KeyValue = GetNumber(KNUM->getText(), LineNum, 2); >>
}
<< WriteFlagsKey (KeyValue, LineNum); >>
";"
;
vfrStatementHidden :
IDH:Hidden << WriteOpByte (IDH->getLine(), EFI_IFR_HIDDEN_OP); >>
Value "="
VAL:Number "," << WriteWord (GetNumber (VAL->getText(), VAL->getLine(), 2)); >>
Key "="
KVAL:Number << WriteWord (GetNumber (KVAL->getText(), KVAL->getLine(), 2)); >>
";"
;
//*****************************************************************************
//
// PARSE:
// suppressif <boolean_expression> { grayoutif } <statements>+ endif;
// Note:
// You can have: suppressif:grayoutif:statements:endif
// suppressif:grayoutif:endif -- serves no purpose
// suppressif:statements:endif
// suppressif:endif -- serves no purpose
//
vfrStatementSuppressIf :
<< ResetFlags (); >>
OPID:SuppressIf << WriteOpByte (OPID->getLine(), EFI_IFR_SUPPRESS_IF_OP); SetIfStart (OPID->getLine()); >>
{
FF:Flags "=" flagsField ( "\|" flagsField )* ","
}
<< WriteFlags (); >> // write the flags field
vfrBooleanExpression
";"
{ suppressIfGrayOutIf } ( suppressIfAndGrayoutIfSubstatements )+
ENDOP:EndIf ";" << WriteOpByte (ENDOP->getLine(), EFI_IFR_END_IF_OP); SetIfStart (0); >>
;
//
// This is the form for a grayoutif nested in a suppressif statement
//
suppressIfGrayOutIf :
<< ResetFlags (); >>
OPID:GrayOutIf << WriteOpByte (OPID->getLine(), EFI_IFR_GRAYOUT_IF_OP); >>
{
FF:Flags "=" flagsField ( "\|" flagsField )* ","
}
<< WriteFlags (); >> // write the flags field
vfrBooleanExpression
";"
;
//*****************************************************************************
//
// PARSE:
// grayoutif { flags = n, } <boolean_expression> endif;
// Note:
// You can have: grayoutif:suppressif:statements:endif
// grayoutif:statements:endif
//
//
vfrStatementGrayOutIf :
<< ResetFlags (); >>
OPID:GrayOutIf << WriteOpByte (OPID->getLine(), EFI_IFR_GRAYOUT_IF_OP); SetIfStart (OPID->getLine()); >>
{
FF:Flags "=" flagsField ( "\|" flagsField )* ","
}
<< WriteFlags (); >> // write the flags field
vfrBooleanExpression
";"
{ grayoutIfSuppressIf } ( suppressIfAndGrayoutIfSubstatements )+
ENDOP:EndIf ";" << WriteOpByte (ENDOP->getLine(), EFI_IFR_END_IF_OP); SetIfStart (0); >>
;
//
// This is the format for a suppressif nested in a grayoutif
//
grayoutIfSuppressIf :
<< ResetFlags (); >>
OPID:SuppressIf << WriteOpByte (OPID->getLine(), EFI_IFR_SUPPRESS_IF_OP); >>
{
FF:Flags "=" flagsField ( "\|" flagsField )* ","
}
<< WriteFlags (); >> // write the flags field
vfrBooleanExpression
";"
;
//
// These are the VFR statements that are valid inside a suppressif or grayoutif statement.
//
suppressIfAndGrayoutIfSubstatements :
vfrStatementOneOf |
vfrStatementTextText |
vfrStatementCheckBox |
vfrStatementNumeric |
vfrStatementDate |
vfrStatementTime |
vfrStatementPassword |
vfrStatementString |
vfrStatementHidden |
vfrStatementGoto |
vfrStatementLabel |
vfrStatementInventory |
vfrStatementOrderedList |
vfrStatementSaveRestoreDefaults
;
//*****************************************************************************
//
// PARSE:
//
// password varid = MyNvData.Password,
// prompt = STRING_TOKEN(STR_PASSWORD_PROMPT),
// help = STRING_TOKEN(STR_PASSWORD_HELP),
// minsize = 6,
// maxsize = 20,
// encoding = 1,
// endpassword;
vfrStatementPassword :
<< UINT32 KeyValue = 0; UINT32 LineNum; ResetFlags (); >>
IDPW:Password << WriteOpByte (IDPW->getLine(), EFI_IFR_PASSWORD_OP); >>
VarId "=" vfrStructFieldNameArray[0] ","
Prompt "=" getStringId ","
KH:Help "=" getStringId "," << LineNum = KH->getLine(); >>
{
FF:Flags "=" flagsField ( "\|" flagsField )* "," << LineNum = FF->getLine(); >>
}
{
Key "=" KNUM:Number "," << LineNum = KNUM->getLine(); KeyValue = GetNumber(KNUM->getText(), LineNum, 2); >>
}
<< WriteFlagsKey (KeyValue, LineNum); >>
MinSize "=" MIN:Number "," << WriteByte (GetNumber (MIN->getText(), MIN->getLine(), 1), 0); >>
MaxSize "=" MAX:Number "," << WriteByte (GetNumber (MAX->getText(), MAX->getLine(), 1), 0); >>
Encoding "=" ENC:Number "," << WriteWord (GetNumber (ENC->getText(), ENC->getLine(), 2)); >>
EndPassword ";"
;
//*****************************************************************************
//
// PARSE:
//
// string varid = MyNv.String,
// prompt = STRING_TOKEN(STR_STRING_PROMPT),
// help = STRING_TOKEN(STR_STRING_HELP),
// flags = INTERACTIVE,
// key = 0x1234,
// minsize = 6,
// maxsize = 0x14,
// endstring;
//
// Since flags and key are optional, we can't use Flags->getLine(). Therefore for error
// reporting we save the line number of the "help" keyword.
//
vfrStatementString :
<< unsigned int KeyValue = 0; UINT32 LineNum; ResetFlags (); >>
IDS:String << WriteOpByte (IDS->getLine(), EFI_IFR_STRING_OP); >>
VarId "=" vfrStructFieldNameArray[0] ","
Prompt "=" getStringId ","
KH:Help "=" getStringId "," << LineNum = KH->getLine(); >>
{
FF:Flags "="
flagsField ( "\|" flagsField )* << LineNum = FF->getLine(); >>
","
}
{
Key "=" KNUM:Number "," << LineNum = KNUM->getLine(); KeyValue = GetNumber(KNUM->getText(), LineNum, 2); >>
}
<< WriteFlagsKey (KeyValue, LineNum); >>
MinSize "=" MIN:Number "," << WriteByte (GetNumber (MIN->getText(), MIN->getLine(), 1), 0); >>
MaxSize "=" MAX:Number "," << WriteByte (GetNumber (MAX->getText(), MAX->getLine(), 1), 0); >>
EndString ";"
;
//*****************************************************************************
//
// PARSE:
// numeric varid = MyIfrNVData.HowOldAreYouInYears,
// prompt = STRING_TOKEN(STR_NUMERIC_PROMPT),
// help = STRING_TOKEN(STR_NUMERIC_HELP),
// flags = INTERACTIVE, // flags is optional
// key = 0x1234, // key is optional if (flags & INTERACTIVE = 0)
// minimum = 0x0,
// maximum = 0xf0,
// step = 1, // step is option, and step=1 if not specified
// default = 0; // default is optional, and default=minimum if not specified
// endnumeric;
//
// Make flags and key optional. However if flags includes INTERACTIVE, then a key is required.
// That check is done in WriteFlagsKey() function.
//
vfrStatementNumeric :
<< UINT32 LineNum, KeyValue = 0; ResetFlags (); >>
IDN:Numeric << WriteOpByte (IDN->getLine(), EFI_IFR_NUMERIC_OP); >>
VarId "=" vfrStructFieldName[2] ","
Prompt "=" getStringId ","
KH:Help "=" getStringId "," << LineNum = KH->getLine(); >>
{
FF:Flags "=" flagsField ( "\|" flagsField )* "," << LineNum = FF->getLine (); >>
}
{
Key "=" KNUM:Number "," << LineNum = KNUM->getLine(); KeyValue = GetNumber(KNUM->getText(), LineNum, 2); >>
}
<< WriteFlagsKey (KeyValue, LineNum); >>
minMaxStepDefault
EndNumeric ";" << WriteMinMaxStepDefault (); >>
;
//
// Parse minimum/maximum/step/default statements. Special cases:
// - if step not specified, then the value is 1
// - if default not specified, then the value is the min value specified
// - if max < min, print a warning and swap the values (changes default too)
//
minMaxStepDefault :
<< InitMinMaxStepDefault (); >>
Minimum "=" MIN:Number "," << SetMinMaxStepDefault (GetNumber (MIN->getText(), MIN->getLine(), 2), 0, MIN->getLine()); >>
Maximum "=" MAX:Number "," << SetMinMaxStepDefault (GetNumber (MAX->getText(), MAX->getLine(), 2), 1, MAX->getLine()); >>
{ Step "=" STEP:Number "," << SetMinMaxStepDefault (GetNumber (STEP->getText(), STEP->getLine(), 2), 2, STEP->getLine()); >> }
{ Default "=" DEF:Number "," << SetMinMaxStepDefault (GetNumber (DEF->getText(), DEF->getLine(), 2), 3, DEF->getLine()); >> }
;
//*****************************************************************************
//
// PARSE:
//
// date year varid = Date.Year, // "Date.Year" is a special case we recognize
// prompt = STRING_TOKEN(STR_DATE_PROMPT),
// help = STRING_TOKEN(STR_DATE_YEAR_HELP),
// minimum = 1939,
// maximum = 2101,
// step = 1,
// default = 1964,
//
// month varid = Date.Month,
// prompt = STRING_TOKEN(STR_DATE_PROMPT),
// help = STRING_TOKEN(STR_DATE_MONTH_HELP),
// minimum = 1,
// maximum = 12,
// step = 1,
// default = 1,
//
// day varid = Date.Day,
// prompt = STRING_TOKEN(STR_DATE_PROMPT),
// help = STRING_TOKEN(STR_DATE_DAY_HELP),
// minimum = 1,
// maximum = 31,
// step = 0x1,
// default = 1,
//
// enddate;
//
vfrStatementDate :
Date
IDY:Year VarId "=" << WriteOpByte (IDY->getLine(), EFI_IFR_DATE_OP); >>
vfrStructFieldName[2] ","
dateTimeSubStatement
IDM:Month VarId "=" << WriteOpByte (IDM->getLine(), EFI_IFR_DATE_OP); >>
vfrStructFieldName[2] ","
dateTimeSubStatement
IDD:Day VarId "=" << WriteOpByte (IDD->getLine(), EFI_IFR_DATE_OP); >>
vfrStructFieldName[2] ","
dateTimeSubStatement
EndDate ";"
;
vfrStatementTime :
Time
IDH:Hour VarId "=" << WriteOpByte (IDH->getLine(), EFI_IFR_TIME_OP); >>
vfrStructFieldName[2] ","
dateTimeSubStatement
IDM:Minute VarId "=" << WriteOpByte (IDM->getLine(), EFI_IFR_TIME_OP); >>
vfrStructFieldName[2] ","
dateTimeSubStatement
IDS:Second VarId "=" << WriteOpByte (IDS->getLine(), EFI_IFR_TIME_OP); >>
vfrStructFieldName[2] ","
dateTimeSubStatement
EndTime ";"
;
//*****************************************************************************
//
// PARSE:
//
// text text = STRING_ID;
// text text = STRING_ID, text = STRING_ID;
// text text = STRING_ID, text = STRING_ID, flags = x, key = y;
//
vfrStatementTextText :
<< ResetFlags (); >>
IDT:Text << WriteOpByte (IDT->getLine(), EFI_IFR_TEXT_OP); >>
Help "=" getStringId ","
Text "="
getStringId // writes string identifier
{ "," Text "=" getStringId
"," Flags "=" flagsField ( "\|" flagsField )* << WriteFlags (); >>
","
Key "=" KNUM:Number << WriteWord (GetNumber(KNUM->getText(), KNUM->getLine(), 2)); >>
}
";"
;
//*****************************************************************************
//
// PARSE:
//
// inventory help = ID, text = ID;
// inventory help = ID, text = id, text = ID;
//
vfrStatementInventory :
IDI:Inventory << WriteOpByte (IDI->getLine(), EFI_IFR_INVENTORY_OP); >>
Help "=" getStringId ","
Text "=" getStringId // writes string identifier
{ "," Text "=" getStringId
}
";"
;
//*****************************************************************************
//
// PARSE:
//
// restore defaults,
// formid = 4,
// prompt = STRING_TOKEN(STR_RESTORE_DEFAULTS_PROMPT),
// help = STRING_TOKEN(STR_RESTORE_DEFAULTS_HELP),
// flags = 0,
// key = 0;
//
// save defaults,
// formid = 4,
// prompt = STRING_TOKEN(STR_SAVE_DEFAULTS_PROMPT),
// help = STRING_TOKEN(STR_SAVE_DEFAULTS_HELP),
// flags = 0,
// key = 0;
//
vfrStatementSaveRestoreDefaults :
<< unsigned int KeyValue = 0; UINT32 LineNum; ResetFlags (); >>
( IDS:Save << WriteOpByte (IDS->getLine(), EFI_IFR_SAVE_DEFAULTS_OP); >>
| IDR:Restore << WriteOpByte (IDR->getLine(), EFI_IFR_RESTORE_DEFAULTS_OP); >>
)
Defaults ","
FormId "=" FRMID:Number "," << WriteWord (GetNumber (FRMID->getText(), FRMID->getLine(), 2));
AddGotoReference (GetNumber (FRMID->getText(), FRMID->getLine(), 2), FRMID->getLine());
>>
Prompt "=" getStringId ","
KH:Help "=" getStringId << LineNum = KH->getLine(); >>
{
"," FF:Flags "=" flagsField ( "\|" flagsField )* << LineNum = FF->getLine(); >>
}
{
"," Key "=" KNUM:Number << LineNum = KNUM->getLine(); KeyValue = GetNumber(KNUM->getText(), LineNum, 2); >>
}
<< WriteFlagsKey (KeyValue, LineNum); >>
";"
;
//*****************************************************************************
//
// PARSE:
//
// flags = 0x10 | DEFAULT | MANUFACTURING | INTERACTIVE | NV_ACCESS | RESET_REQUIRED | LATE_CHECK
//
//
flagsField :
VAL:Number << SetFlags (GetNumber(VAL->getText(), VAL->getLine(), 4), VAL->getLine()); >>
| IF:InteractiveFlag << SetFlags (EFI_IFR_FLAG_INTERACTIVE, IF->getLine()); >>
| MF:ManufacturingFlag << SetFlags (EFI_IFR_FLAG_MANUFACTURING, MF->getLine()); >>
| DF:DefaultFlag << SetFlags (EFI_IFR_FLAG_DEFAULT, DF->getLine()); >>
| NV:NVAccessFlag << SetFlags (EFI_IFR_FLAG_NV_ACCESS, NV->getLine()); >>
| RR:ResetRequiredFlag << SetFlags (EFI_IFR_FLAG_RESET_REQUIRED, RR->getLine()); >>
| LC:LateCheckFlag << SetFlags (EFI_IFR_FLAG_LATE_CHECK, LC->getLine()); >>
;
dateTimeSubStatement :
Prompt "=" getStringId ","
Help "=" getStringId ","
<< WriteByte (0, 0); WriteWord (0); >> // bogus flags and key
minMaxStepDefault << WriteMinMaxStepDefault (); >>
;
vfrStatementCheckBox :
<< UINT32 LineNum, KeyValue = 0; ResetFlags (); >>
IDCB:CheckBox << WriteOpByte (IDCB->getLine(), EFI_IFR_CHECKBOX_OP); >>
VarId "=" vfrStructFieldName[1] ","
Prompt "=" getStringId ","
Help "=" getStringId ","
FF:Flags "=" flagsField ( "\|" flagsField )* "," << LineNum = FF->getLine(); >>
{
Key "=" KV:Number "," << LineNum = KV->getLine(); KeyValue = GetNumber(KV->getText(), LineNum, 2); >>
}
<< WriteFlagsKey (KeyValue, LineNum); >>
EndCheckBox ";"
;
vfrStatementSubTitle :
IDS:Subtitle Text "=" << WriteOpByte (IDS->getLine(), EFI_IFR_SUBTITLE_OP); >>
getStringId // writes string indentifier
";"
;
//*****************************************************************************
//
// PARSE:
// banner
// title = STRING_TOKEN(STR_BANNER_TITLE),
// line 1,
// align center; // or left or right
//
// banner,
// title = STRING_TOKEN(STR_BANNER_TITLE), timeout = 100;
//
vfrStatementBanner :
IDB:Banner { "," } << WriteOpByte (IDB->getLine(), EFI_IFR_BANNER_OP); >>
Title "=" getStringId ","
(
Line VAL:Number "," << WriteWord (GetNumber(VAL->getText(), VAL->getLine(), 2)); >>
Align
( Left << WriteByte (EFI_IFR_BANNER_ALIGN_LEFT, 0); >>
| Center << WriteByte (EFI_IFR_BANNER_ALIGN_CENTER, 0); >>
| Right << WriteByte (EFI_IFR_BANNER_ALIGN_RIGHT, 0); >>
) ";"
|
Timeout "=" TO:Number ";" << WriteWord (GetNumber(TO->getText(), TO->getLine(), 2)); >>
<< WriteByte (EFI_IFR_BANNER_TIMEOUT, 0); >>
)
;
//*****************************************************************************
//
// PARSE:
// oneof varid = MyNv.OneOfData,
// prompt = STRING_TOKEN(STR_ONE_OF_PROMPT),
// help = STRING_TOKEN(STR_ONE_OF_HELP),
// option text = STRING_TOKEN(STR_ONE_OF_TEXT),
// value = 0,
// flags = DEFAULT | INTERACTIVE;
//
// supressif/grayoutif are supported inside oneof stmt.
// We do not restrict the number of oneOfOptionText to >=2, but >=1.
// The situation that all oneOfOptionText are suppressed is also possiable.
//
vfrStatementOneOf :
<< ResetFlags (); >>
IDOO:OneOf << WriteOpByte (IDOO->getLine(), EFI_IFR_ONE_OF_OP); >>
VarId "=" vfrStructFieldName[2] ","
Prompt "=" getStringId "," // writes string identifier
Help "=" getStringId "," // writes string identifier
( oneOfOptionText )+ // there must be at least 1 option to be choosed, not 2.
IDEOO:EndOneOf ";" << TestOneOfFlags (IDEOO->getLine()); WriteOpByte (IDEOO->getLine(), EFI_IFR_END_ONE_OF_OP); >>
;
//*****************************************************************************
//
// PARSE:
//
// orderedlist varid = MyNv.OrderedListData,
// prompt = STRING_TOKEN(STR_ORDERED_LIST_PROMPT),
// help = STRING_TOKEN(STR_ORDERED_LIST_HELP),
// option text = STRING_TOKEN(STR_ORDERED_LIST_TEXT), value = 0, flags = INTERACTIVE;
// -- additional option text --
// endlist;
//
vfrStatementOrderedList :
<< ResetFlags (); InitOrderedList(); >>
IDOL:OrderedList << WriteOpByte (IDOL->getLine(), EFI_IFR_ORDERED_LIST_OP); >>
VarId "=" vfrStructFieldNameArray[1] ","
Prompt "=" getStringId "," // writes string identifier
Help "=" getStringId "," // writes string identifier
orderedListOptionText ( orderedListOptionText )+
IDEOL:EndList ";" << WriteOpByte (IDEOL->getLine(), EFI_IFR_END_OP); EndOrderedList(IDEOL->getLine()); >>
;
//*****************************************************************************
//
// PARSE:
//
// option text = STRING_TOKEN(STRING_ID), value = 0 flags = 99;
//
// Differs from the oneOfOptionText in that we don't allow the DEFAULT flag to
// be set, and value cannot be 0.
//
orderedListOptionText :
<< UINT32 KeyValue = 0; >>
IDO:Option << WriteOpByte (IDO->getLine(), EFI_IFR_ONE_OF_OPTION_OP); >>
Text "=" getStringId "," // writes string identifier
Value "=" WVAL:Number "," <<
if (GetNumber(WVAL->getText(), WVAL->getLine(), 2) == 0) {
PrintErrorMessage (WVAL->getLine(), "value=0 is invalid for ordered lists", NULL);
} else {
WriteWord (GetNumber(WVAL->getText(), WVAL->getLine(), 2));
}
>>
FF:Flags "=" orderedListFlagsField
("\|" orderedListFlagsField )*
{
"," Key "=" KV:Number << KeyValue = GetNumber (KV->getText(), KV->getLine(), 2); >>
}
<< WriteFlagsKey (KeyValue, FF->getLine()); >>
";" << mOptionCount++; >>
;
//*****************************************************************************
//
// PARSE:
//
// flags = 0x10 | DEFAULT | MANUFACTURING | INTERACTIVE | NV_ACCESS | RESET_REQUIRED | LATE_CHECK
//
// The ordered list flags field cannot have a default.
//
orderedListFlagsField :
VAL:Number << SetFlags (GetNumber(VAL->getText(), VAL->getLine(), 4), VAL->getLine()); >>
| IF:InteractiveFlag << SetFlags (EFI_IFR_FLAG_INTERACTIVE, IF->getLine()); >>
| MF:ManufacturingFlag << SetFlags (EFI_IFR_FLAG_MANUFACTURING, MF->getLine()); >>
| NV:NVAccessFlag << SetFlags (EFI_IFR_FLAG_NV_ACCESS, NV->getLine()); >>
| RR:ResetRequiredFlag << SetFlags (EFI_IFR_FLAG_RESET_REQUIRED, RR->getLine()); >>
| LC:LateCheckFlag << SetFlags (EFI_IFR_FLAG_LATE_CHECK, LC->getLine()); >>
| DF:DefaultFlag << PrintWarningMessage (DF->getLine(), "DEFAULT flag not valid for ordered lists", NULL); >>
;
//
// Parse references to VFR structure field names of form "MyNvStructure.Field".
// This implementation is specific to strings, passwords, and references in an
// ordered list statement because we want to specify the size of the entire
// field, rather than just one element. Then call a function to write out its
// offset and length.
//
vfrStructFieldNameArray[int FieldWidth] :
<< int ArrayIndex = 1; char IsArrayIndex = 0; >>
SName:StringIdentifier
"."
SFieldName:StringIdentifier
{ OpenBracket AIndex:Number CloseBracket << ArrayIndex = GetNumber(AIndex->getText(), AIndex->getLine(), 4); IsArrayIndex = 1; >> }
<<
WriteFieldOffset (1,
SName->getText(),
SName->getLine(),
SFieldName->getText(),
SFieldName->getLine(),
ArrayIndex,
IsArrayIndex,
FieldWidth,
1
);
>>
;
//
// Parse references to VFR structure field names of form "MyNvStructure.Field",
// then call a function to write out its offset and length.
//
vfrStructFieldName[int FieldWidth] :
<< int ArrayIndex = 1; char IsArrayIndex = 0; >>
SName:StringIdentifier
"."
SFieldName:StringIdentifier
{ OpenBracket AIndex:Number CloseBracket << ArrayIndex = GetNumber(AIndex->getText(), AIndex->getLine(), 4); IsArrayIndex = 1; >> }
<<
WriteFieldOffset (1,
SName->getText(),
SName->getLine(),
SFieldName->getText(),
SFieldName->getLine(),
ArrayIndex,
IsArrayIndex,
FieldWidth,
0
);
>>
;
//*****************************************************************************
//
// PARSE:
//
// MyNvStructure.FieldName[4]
//
// Parse references to VFR structure field names of form "MyNvStructure.Field",
// then call a function to write out the offset with no length.
//
vfrStructFieldNameNL[int FieldWidth] :
<< int ArrayIndex = 1; char IsArrayIndex = 0; >>
SName:StringIdentifier
"."
SFieldName:StringIdentifier
{ OpenBracket AIndex:Number CloseBracket << ArrayIndex = GetNumber(AIndex->getText(), AIndex->getLine(), 4); IsArrayIndex = 1; >> }
<<
WriteFieldOffset (0,
SName->getText(),
SName->getLine(),
SFieldName->getText(),
SFieldName->getLine(),
ArrayIndex,
IsArrayIndex,
FieldWidth,
0
);
>>
;
//*****************************************************************************
//
// PARSE:
// suppressif TRUE OR FALSE;
// grayoutif FALSE OR TRUE;
// option text = STRING_TOKEN(STRING_ID), value = 0 flags = 99;
// option text = STRING_TOKEN(STRING_ID2), value = 1 flags = 98;
// endif;
//
oneOfOptionText :
suppressIfOptionText |
grayOutIfOptionText |
commonOptionText
;
suppressIfOptionText :
<< ResetFlags (); >>
OPID:SuppressIf << WriteOpByte (OPID->getLine(), EFI_IFR_SUPPRESS_IF_OP); SetIfStart (OPID->getLine()); >>
{
FF:Flags "=" flagsField ( "\|" flagsField )* ","
}
<< WriteFlags (); >> // write the flags field
vfrBooleanExpression
";"
{ suppressIfGrayOutIf } ( commonOptionText )+
ENDOP:EndIf ";" << WriteOpByte (ENDOP->getLine(), EFI_IFR_END_IF_OP); SetIfStart (0); >>
;
grayOutIfOptionText :
<< ResetFlags (); >>
OPID:GrayOutIf << WriteOpByte (OPID->getLine(), EFI_IFR_GRAYOUT_IF_OP); SetIfStart (OPID->getLine()); >>
{
FF:Flags "=" flagsField ( "\|" flagsField )* ","
}
<< WriteFlags (); >> // write the flags field
vfrBooleanExpression
";"
{ grayoutIfSuppressIf } ( commonOptionText )+
ENDOP:EndIf ";" << WriteOpByte (ENDOP->getLine(), EFI_IFR_END_IF_OP); SetIfStart (0); >>
;
commonOptionText :
<< UINT32 KeyValue = 0; >>
IDO:Option << WriteOpByte (IDO->getLine(), EFI_IFR_ONE_OF_OPTION_OP); >>
Text "=" getStringId "," // writes string identifier
Value "=" WVal:Number "," << WriteWord (GetNumber(WVal->getText(), WVal->getLine(), 2)); >>
FF:Flags "=" flagsField ("\|" flagsField )*
{
"," Key "=" KV:Number << KeyValue = GetNumber (KV->getText(), KV->getLine(), 2); >>
}
<< WriteFlagsKey (KeyValue, FF->getLine()); >>
";" << mOptionCount++; >>
;
//
// Gets a string identifier. It must be a numeric value of form:
//
// STRING_TOKEN(100)
//
getStringId :
<< unsigned short StrId; >>
StringToken OpenParen
IdVal:Number << StrId = GetNumber (IdVal->getText(), IdVal->getLine(), 2); WriteStringIdWord (StrId); >>
CloseParen
;
//******************************************************************************
//
// Parser class definition.
//
class EfiVfrParser {
<<
//
// Parser definitions go here
//
private:
STRUCT_DEFINITION *mFirstStructDefinition;
STRUCT_DEFINITION *mLastStructDefinition;
INT32 mNvDataStructSize;
INT32 mNonNvDataStructSize;
//
// Flag to indicate that we're processing a ideqid VFR statement so that
// we can do late checks on the statement.
//
INT32 mIdEqIdStmt;
INT32 mLastNVVariableDataSize;
GOTO_REFERENCE *mGotoReferences;
FORM_ID_VALUE *mFormIdValues;
VfrOpcodeHandler mOpcodeHandler;
UINT16_LIST *mUint16List;
UINT16_LIST *mLastUint16;
UINT16_LIST *mDefinedLabels;
UINT16_LIST *mDefinedVarStoreId;
UINT16_LIST *mLastDefinedVarStoreId;
UINT32 mMinimumValue, mMaximumValue, mStepValue, mDefaultValue;
UINT32 mStmtFlags;
UINT32 mSubStmtFlags;
UINT32 mSubStmtFlagsLineNum;
EFI_GUID mFormSetGuid;
UINT8 mNvDataStructDefined;
UINT16 mClass, mSubclass;
UINT32 mIfStart;
UINT32 mOptionCount; // how many "option" fields in a given statement
UINT32 mLastVarIdSize;
UINT8 mOutput;
public:
VOID
EfiVfrParser::SetIfStart (
UINT32 LineNum
)
/*++
Routine Description:
Invoked during VFR parsing when an "if" is encountered. Save the
source line number so we can point to it if we don't find a
corresponding endif later.
Arguments:
LineNum - source line number where the "if" was parsed.
Returns:
None
--*/
{
mIfStart = LineNum;
}
VOID
EfiVfrParser::SetClass (
UINT32 LineNum,
UINT32 Value
)
/*++
Routine Description:
Invoked during VFR parsing when a "class" statement is found. Check the
range on the class value and save it for later.
Arguments:
LineNum - source line number where the class statement was parsed.
Value - the class value
Returns:
None
--*/
{
if (Value & 0xFFFF0000) {
PrintWarningMessage (LineNum, NULL, "class value exceeds maximum allowed");
}
mClass |= (UINT16)Value;
}
VOID
EfiVfrParser::SetSubclass (
UINT32 LineNum,
UINT32 Value
)
/*++
Routine Description:
Invoked during VFR parsing when a subclass statement is found. Check the
range on the value and save it for later.
Arguments:
LineNum - source line number where the class statement was parsed.
Value - the subclass value from the VFR statement
Returns:
None
--*/
{
if (Value & 0xFFFF0000) {
PrintWarningMessage (LineNum, NULL, "subclass value exceeds maximum allowed");
}
mSubclass |= (UINT16)Value;
}
VOID EfiVfrParser::WriteClass ()
{
WriteWord (mClass);
mClass = 0;
}
VOID EfiVfrParser::WriteSubclass ()
{
WriteWord (mSubclass);
mSubclass = 0;
}
VOID EfiVfrParser::WriteIfrBytes ()
{
mOpcodeHandler.WriteIfrBytes ();
}
VOID
EfiVfrParser::WriteFlagsKey (
UINT32 KeyValue,
UINT32 LineNum
)
/*++
Routine Description:
Write out the flags and key values from the previous VFR statement.
Many statements take a flags/key pair. If not specified, then 0
values are written out. However do not allow an interactive flags field
to be specified if no key value is specified. Also, if NV_ACCESS flag
is set but INTERACTIVE is not, then set interactive and issue a warning.
Arguments:
KeyValue - the key value from the VFR statement
LineNum - source line number where the statement was parsed
Returns:
None
--*/
{
if ((mSubStmtFlags & EFI_IFR_FLAG_INTERACTIVE) && (KeyValue == 0)) {
PrintErrorMessage (LineNum, NULL, "invalid or missing key value - required with INTERACTIVE");
}
if ((mSubStmtFlags & EFI_IFR_FLAG_NV_ACCESS) && !(mSubStmtFlags & EFI_IFR_FLAG_INTERACTIVE)) {
PrintWarningMessage (LineNum, NULL, "NV_ACCESS without INTERACTIVE has no effect -- setting INTERACTIVE");
mSubStmtFlags |= EFI_IFR_FLAG_INTERACTIVE;
}
WriteFlags ();
WriteWord (KeyValue);
}
VOID
EfiVfrParser::InitOrderedList ()
{
mOptionCount = 0;
}
VOID
EfiVfrParser::EndOrderedList (
UINT32 LineNum
)
{
if (mLastVarIdSize < mOptionCount) {
PrintErrorMessage (LineNum, NULL, "number of options exceeds the variable store size");
}
}
VOID
EfiVfrParser::ResetFlags ()
/*++
Routine Description:
Flags are set for each substatement in a given one-of statement.
To make sure there are no conflicts, for example setting DEFAULT on
more than one substatement, we keep track of the flags at a statement
level and a substatement level. This function resets the flags so
we get a fresh start.
Arguments:
None
Returns:
None
--*/
{
mStmtFlags = 0;
mSubStmtFlagsLineNum = 0;
mSubStmtFlags = 0;
}
//
// Test validity of flags value for a one-of statement.
//
VOID
EfiVfrParser::TestOneOfFlags (
UINT32 LineNum
)
{
//
// One of the fields must have had the default bit set
//
if ((mStmtFlags & EFI_IFR_FLAG_DEFAULT) == 0) {
PrintWarningMessage (LineNum, "default value must be specified", NULL);
}
}
VOID
EfiVfrParser::SetFlags (
UINT32 Flags,
UINT32 LineNum
)
{
//
// Check for redefinitions and invalid combinations
//
if (mStmtFlags & Flags & EFI_IFR_FLAG_MANUFACTURING) {
PrintErrorMessage (LineNum, "MANUFACTURING", "a field with this flag already defined");
}
if (mStmtFlags & Flags & EFI_IFR_FLAG_DEFAULT) {
PrintErrorMessage (LineNum, "DEFAULT", "a field with this flag already defined");
}
mSubStmtFlags |= Flags;
mSubStmtFlagsLineNum = LineNum;
}
VOID
EfiVfrParser::WriteFlags ()
{
//
// Check value for validity
//
if (mSubStmtFlags & ~(EFI_IFR_FLAG_DEFAULT |
EFI_IFR_FLAG_MANUFACTURING |
EFI_IFR_FLAG_INTERACTIVE |
EFI_IFR_FLAG_NV_ACCESS |
EFI_IFR_FLAG_RESET_REQUIRED |
EFI_IFR_FLAG_LATE_CHECK )) {
PrintWarningMessage (mSubStmtFlagsLineNum, "invalid bits defined in flag", NULL);
}
WriteByte ((UINT8)mSubStmtFlags, 'F');
//
// We can now clear the substatement flags
//
mStmtFlags |= mSubStmtFlags;
mSubStmtFlags = 0;
}
//
// When we parse a min/max/step/default sequence, save off the values for
// later use. Call this first to init the values.
//
VOID
EfiVfrParser::InitMinMaxStepDefault ()
{
mMinimumValue = 0;
mMaximumValue = 0;
mStepValue = 1;
mDefaultValue = 0;
}
VOID
EfiVfrParser::WriteMinMaxStepDefault ()
{
WriteWord (mMinimumValue);
WriteWord (mMaximumValue);
WriteWord (mStepValue);
WriteWord (mDefaultValue);
}
VOID
EfiVfrParser::SetMinMaxStepDefault (
UINT16 Value,
INT32 MMSD,
INT32 LineNum
)
{
UINT16 TempValue;
//
// Min specified
//
if (MMSD == 0) {
mMinimumValue = Value;
mDefaultValue = Value;
//
// Max specified
//
} else if (MMSD == 1) {
mMaximumValue = Value;
//
// If min > max, then swap the values. That includes resetting the default
// value as well.
//
if (mMinimumValue > mMaximumValue) {
PrintWarningMessage (LineNum, NULL, "maximum < minimum");
TempValue = Value;
mMaximumValue = mMinimumValue;
mMinimumValue = TempValue;
mDefaultValue = mMinimumValue;
}
//
// Step specified
//
} else if (MMSD == 2) {
mStepValue = Value;
//
// Default specified. Make sure min <= default <= max.
//
} else if (MMSD == 3) {
mDefaultValue = Value;
if (mMinimumValue > Value) {
PrintErrorMessage (LineNum, NULL, "default value < minimum value");
} else if (Value > mMaximumValue) {
PrintErrorMessage (LineNum, NULL, "default value > maximum value");
}
} else {
PrintErrorMessage (LineNum, "application error", "internal MMSD error");
}
}
VOID
EfiVfrParser::AddLabel (
UINT32 LabelNumber,
UINT32 LineNum
)
{
UINT16_LIST *Label;
//
// Added a label from the user VFR script. Make sure they haven't already
// defined the same label elsewhere
//
for (Label = mDefinedLabels; Label != NULL; Label = Label->Next) {
if (Label->Value == LabelNumber) {
PrintErrorMessage (LineNum, NULL, "label already defined");
PrintErrorMessage (Label->LineNum, NULL, "previous definition of redefined label");
break;
}
}
Label = (UINT16_LIST *)malloc (sizeof (UINT16_LIST));
if (Label == NULL) {
PrintErrorMessage (0, NULL, "memory allocation error");
return;
}
memset ((char *)Label, 0, sizeof (UINT16_LIST));
Label->Value = LabelNumber;
Label->LineNum = LineNum;
Label->Next = mDefinedLabels;
mDefinedLabels = Label;
}
VOID
EfiVfrParser::QueueIdEqValList (
UINT16 Value
)
{
UINT16_LIST *U16;
U16 = (UINT16_LIST *)malloc (sizeof (UINT16_LIST));
if (U16 == NULL) {
Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failed");
} else {
memset ((char *)U16, 0, sizeof (UINT16_LIST));
U16->Value = Value;
if (mUint16List == NULL) {
mUint16List = U16;
} else {
mLastUint16->Next = U16;
}
mLastUint16 = U16;
}
}
VOID
EfiVfrParser::FlushQueueIdEqValList ()
{
UINT32 Count;
//
// We queued up a list of IdEqValList items. The IFR requires a count
// followed by the actual values. Do it.
//
Count = 0;
mLastUint16 = mUint16List;
while (mLastUint16 != NULL) {
Count++;
mLastUint16 = mLastUint16->Next;
}
// BUGBUG -- check for more than 16K items?
WriteWord (Count);
//
// Now write the values.
//
mLastUint16 = mUint16List;
while (mLastUint16 != NULL) {
WriteWord ((UINT32)mLastUint16->Value);
mLastUint16 = mLastUint16->Next;
}
//
// Free up the list
//
mLastUint16 = mUint16List;
while (mUint16List != NULL) {
mLastUint16 = mUint16List->Next;
free (mUint16List);
mUint16List = mLastUint16;
}
}
VOID
EfiVfrParser::PrintErrorMessage (
UINT32 LineNum,
CHAR8 *Msg1,
CHAR8 *Msg2
)
{
char *FileName;
if (LineNum != 0) {
FileName = ConvertLineNumber ((UINT32 *)&LineNum);
Error (FileName, LineNum, 0, Msg1, Msg2);
} else {
Error (PROGRAM_NAME, 0, 0, Msg1, Msg2);
}
}
VOID
EfiVfrParser::PrintWarningMessage (
UINT32 LineNum,
CHAR8 *Msg1,
CHAR8 *Msg2
)
{
char *FileName;
if (LineNum != 0) {
FileName = ConvertLineNumber ((UINT32 *)&LineNum);
Warning (FileName, LineNum, 0, Msg1, Msg2);
} else {
Warning (PROGRAM_NAME, 0, 0, Msg1, Msg2);
}
}
VOID
EfiVfrParser::syn (
ANTLRAbstractToken *Tok,
ANTLRChar *Egroup,
SetWordType *Eset,
ANTLRTokenType ETok,
INT32 Huh
)
/*++
Routine Description:
Called by the parser base class as a result of parse syntax errors.
Arguments:
Tok - token that caused the error
Egroup - not sure
Eset - index in token table of the expected token
Huh - not sure
Returns:
NA
--*/
{
char *FileName;
UINT32 LineNum;
LineNum = Tok->getLine ();
FileName = ConvertLineNumber ((UINT32 *)&LineNum);
//
// Sometimes the token number is 0, in which case I don't know what to
// print.
//
if (ETok == 0) {
Error (FileName, LineNum, 0, Tok->getText (), "unexpected token");
} else {
//
// If we were expecting an endif, then report the line where the corresponding
// IF began.
//
if ((strcmp (_token_tbl[ETok], "endif") == 0) && (mIfStart != 0)) {
LineNum = mIfStart;
FileName = ConvertLineNumber (&LineNum);
Error (FileName, LineNum, 0, "statement missing corresponding endif", NULL);
} else {
Error (FileName, LineNum, 0, Tok->getText (), "expected %s", _token_tbl[ETok]);
}
}
}
VOID
EfiVfrParser::init()
/*++
Routine Description:
Initializations function for our parser.
Arguments:
None.
Returns:
None.
--*/
{
ANTLRParser::init();
//
// Used for queuing a variable list of UINT16's
//
mUint16List = NULL;
mLastUint16 = NULL;
mFirstStructDefinition = NULL;
mLastStructDefinition = NULL;
mNvDataStructSize = 0;
mNonNvDataStructSize = 0;
mNvDataStructDefined = 0;
mGotoReferences = NULL;
mFormIdValues = NULL;
mDefinedLabels = NULL;
mClass = 0;
mSubclass = 0;
mIfStart = 0;
mDefinedVarStoreId = NULL;
mLastDefinedVarStoreId = NULL;
mIdEqIdStmt = 0;
mLastNVVariableDataSize = 0;
memset ((char *)&mFormSetGuid, 0, sizeof (EFI_GUID));
}
//
// Destructor for the parser.
//
EfiVfrParser::~EfiVfrParser(VOID)
{
Cleanup();
}
VOID
EfiVfrParser::Cleanup (VOID)
/*++
Routine Description:
Free memory allocated during parsing
Arguments:
None.
Returns:
None.
--*/
{
STRUCT_DEFINITION *NextStruct;
STRUCT_FIELD_DEFINITION *NextField;
UINT8 Buff[6];
UINT16_LIST *NextU16List;
//
// Free up the structure definitions if any
//
while (mFirstStructDefinition != NULL) {
//
// Free up all the fields for this struct
//
while (mFirstStructDefinition->Field != NULL) {
NextField = mFirstStructDefinition->Field->Next;
free (mFirstStructDefinition->Field->Name);
free (mFirstStructDefinition->Field);
mFirstStructDefinition->Field = NextField;
}
NextStruct = mFirstStructDefinition->Next;
free (mFirstStructDefinition->Name);
free (mFirstStructDefinition);
mFirstStructDefinition = NextStruct;
}
//
// Free up the goto references and form id defines
//
FreeGotoReferences ();
//
// Free up label list
//
while (mDefinedLabels != NULL) {
NextU16List = mDefinedLabels->Next;
delete (mDefinedLabels);
mDefinedLabels = NextU16List;
}
//
// Free up the list of defined variable storage IDs
//
while (mDefinedVarStoreId != NULL) {
NextU16List = mDefinedVarStoreId->Next;
delete (mDefinedVarStoreId);
mDefinedVarStoreId = NextU16List;
}
}
INT32
EfiVfrParser::AtoX (
CHAR8 *HexString,
INT32 NumBytes,
UINT32 *HexValue
)
/*++
Routine Description:
Given a pointer to a ascii hex string, convert to a number with the given
number of bytes.
Arguments:
HexString - pointer to a string of format 30BCA
Size - number of bytes to convert
HexValue - return result
Returns:
The number of bytes converted.
--*/
{
INT32 Count;
INT32 Value;
*HexValue = 0;
Count = 0;
while (Count < NumBytes) {
if ((*HexString >= '0') && (*HexString <= '9')) {
Value = *HexString - '0';
} else if ((*HexString >= 'a') && (*HexString <= 'f')) {
Value = *HexString - 'a' + 10;
} else if ((*HexString >= 'A') && (*HexString <= 'F')) {
Value = *HexString - 'A' + 10;
} else {
return Count;
}
HexString++;
*HexValue = (*HexValue << 4) | Value;
if ((*HexString >= '0') && (*HexString <= '9')) {
Value = *HexString - '0';
} else if ((*HexString >= 'a') && (*HexString <= 'f')) {
Value = *HexString - 'a' + 10;
} else if ((*HexString >= 'A') && (*HexString <= 'F')) {
Value = *HexString - 'A' + 10;
} else {
return Count;
}
*HexValue = (*HexValue << 4) | Value;
HexString++;
Count++;
}
return Count;
}
VOID
EfiVfrParser::WriteGuidValue (
UINT32 TokenLineNum,
CHAR8 *G1,
CHAR8 *G2,
CHAR8 *G3,
CHAR8 *G4,
CHAR8 *G5,
CHAR8 *G6,
CHAR8 *G7,
CHAR8 *G8,
CHAR8 *G9,
CHAR8 *G10,
CHAR8 *G11
)
/*++
Routine Description:
A Guid was parsed, likely of format:
#define MY_GUID { 0x12345678, 0xAABB, 0xCCDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }
Write out the value.
Arguments:
TokenLineNum - line number where the guid was used
G1-G11 - the 11 fields of the guid value
Returns:
None.
--*/
{
UINT32 Value;
INT32 Loop;
mFormSetGuid.Data1 = GetNumber (G1, TokenLineNum, 4);
mFormSetGuid.Data2 = (UINT16)GetNumber (G2, TokenLineNum, 2);
mFormSetGuid.Data3 = (UINT16)GetNumber (G3, TokenLineNum, 2);
mFormSetGuid.Data4[0] = (UINT8)GetNumber (G4, TokenLineNum, 1);
mFormSetGuid.Data4[1] = (UINT8)GetNumber (G5, TokenLineNum, 1);
mFormSetGuid.Data4[2] = (UINT8)GetNumber (G6, TokenLineNum, 1);
mFormSetGuid.Data4[3] = (UINT8)GetNumber (G7, TokenLineNum, 1);
mFormSetGuid.Data4[4] = (UINT8)GetNumber (G8, TokenLineNum, 1);
mFormSetGuid.Data4[5] = (UINT8)GetNumber (G9, TokenLineNum, 1);
mFormSetGuid.Data4[6] = (UINT8)GetNumber (G10, TokenLineNum, 1);
mFormSetGuid.Data4[7] = (UINT8)GetNumber (G11, TokenLineNum, 1);
WriteDWord (mFormSetGuid.Data1, 'G');
WriteWord (mFormSetGuid.Data2);
WriteWord (mFormSetGuid.Data3);
WriteByte (mFormSetGuid.Data4[0], 0);
WriteByte (mFormSetGuid.Data4[1], 0);
WriteByte (mFormSetGuid.Data4[2], 0);
WriteByte (mFormSetGuid.Data4[3], 0);
WriteByte (mFormSetGuid.Data4[4], 0);
WriteByte (mFormSetGuid.Data4[5], 0);
WriteByte (mFormSetGuid.Data4[6], 0);
WriteByte (mFormSetGuid.Data4[7], 0);
}
VOID
EfiVfrParser::WriteFieldOffset (
INT8 WriteLength,
CHAR8 *StructName,
INT32 LineNum1,
CHAR8 *FieldName,
INT32 LineNum2,
INT32 ArrayIndex,
INT8 IsArrayIndex,
INT32 FieldWidth,
INT8 WriteArraySize
)
/*++
Routine Description:
A VFR script referenced the NV store structure. Given the structure's name
and the field's name, write the offset of the field to the output file.
Arguments:
WriteLength - write the field length byte out
StructName - name of the NV store structure
LineNum1 - line number in the VFR where we are (for error printing)
FieldName - the name of the field within the NV store structure
LineNum2 - line number in the VFR where FieldName is referenced
ArrayIndex - the index specified, for example NV_DATA.Field[ArrayIndex]
IsArrayIndex - non-zero if an array index was specified
FieldWidth - expected size for the Field (1 byte? 2 bytes?)
WriteArraySize - write the size of the entire field, not the size of a single element
Returns:
None.
--*/
{
STRUCT_DEFINITION *StructDef;
STRUCT_FIELD_DEFINITION *FieldDef;
UINT32 Offset;
UINT32 VarSize;
CHAR8 Msg[100];
//
// If we're writing an array size, then they better have referenced the field without an
// index.
//
if (WriteArraySize && IsArrayIndex) {
sprintf (Msg, "array index specified where an array is required");
PrintErrorMessage (LineNum2, FieldName, Msg);
return;
}
//
// Look through our list of known structures for a match
//
for (StructDef = mFirstStructDefinition; StructDef != NULL; StructDef = StructDef->Next) {
//
// Check for matching structure name
//
if (strcmp (StructDef->Name, StructName) == 0) {
//
// Mark it as referenced (for debug purposes only). Check the
// flag that indicates that we have already found a varstore VFR
// statement for it.
//
StructDef->Referenced++;
if (StructDef->VarStoreIdValid == 0) {
//
// Set it valid so we don't flag it multiple times, then emit the error
//
StructDef->VarStoreIdValid = 1;
PrintErrorMessage (LineNum1, StructName, "varstore statement missing for this variable store");
}
//
// Let the opcode-handler know which variable storage we're now using
//
if (mIdEqIdStmt) {
mOpcodeHandler.SetSecondaryVarStoreId (StructDef->VarStoreId);
} else {
mOpcodeHandler.SetVarStoreId (StructDef->VarStoreId);
}
//
// Found matching structure name. Now find the matching field name
//
for (FieldDef = StructDef->Field; FieldDef != NULL; FieldDef = FieldDef->Next) {
if (strcmp (FieldDef->Name, FieldName) == 0) {
//
// Make sure the variable size is valid
//
if ((FieldWidth != 0) && (FieldDef->DataSize > FieldWidth)) {
sprintf (Msg, "field width exceeds %d byte%c", FieldWidth, FieldWidth == 1 ? ' ' : 's');
PrintErrorMessage (LineNum2, FieldName, Msg);
}
//
// If they specified an index (MyVfrData.FieldX[10]), then make sure that the
// data structure was declared as an array, and that the index is in bounds.
// If they did not specify an index, then we'll assume 0. This is required for
// strings.
//
if (IsArrayIndex) {
VarSize = FieldDef->DataSize;
if (FieldDef->IsArray == 0) {
PrintErrorMessage (LineNum2, FieldName, "field is not declared as an array");
return;
}
if (FieldDef->ArrayLength < ArrayIndex) {
PrintErrorMessage (LineNum2, FieldName, "array index exceeds declared size of field");
return;
}
} else {
if (FieldDef->IsArray) {
VarSize = FieldDef->DataSize * FieldDef->ArrayLength;
} else {
VarSize = FieldDef->DataSize;
}
}
//
// If we're in the middle of a ideqid VFR statement, then this is the second
// variable ID that we're now processing. Make sure that its size is the same
// as the first variable.
//
if (mIdEqIdStmt) {
if (mLastVarIdSize != VarSize) {
PrintErrorMessage (LineNum2, FieldName, "variables must have the same size");
return;
}
}
mLastVarIdSize = VarSize;
//
// If we're supposed to write an array size, then require it to be an array
//
if (WriteArraySize && !FieldDef->IsArray) {
PrintErrorMessage (LineNum2, FieldName, "array required");
return;
}
//
// Write the variable offset and size. If we're in the non-NV structure, then
// set the offset beyond the NV data structure size.
//
Offset = FieldDef->Offset + FieldDef->DataSize * (ArrayIndex - 1);
if (StructDef->IsNonNV) Offset += mNvDataStructSize;
WriteWord (Offset);
if (WriteLength) {
if (WriteArraySize) {
if (FieldDef->DataSize * FieldDef->ArrayLength > 255) {
PrintErrorMessage (LineNum2, FieldName, "array size exceeds 255 maximum encoding limit");
return;
}
WriteByte (FieldDef->DataSize * FieldDef->ArrayLength, 0);
} else {
WriteByte (FieldDef->DataSize, 0);
}
}
return;
}
}
sprintf (Msg, "structure %s does not have a field named '%s'", StructName, FieldName);
PrintErrorMessage (LineNum2, Msg, NULL);
PrintErrorMessage (StructDef->LineNum, "see structure definition", NULL);
return;
}
}
//
// The structure was not found in the defined list. See if it's the "Date" structure
//
if (strcmp (StructName, "Date") == 0) {
//
// BUGBUG -- remove support for Date and Time as valid structure
// names. They should use the NON_NV_DATA_MAP structure for this.
//
// Someone specified Date.Years|Months|Days
// BUGBUG -- define some constants for the IDs used here
// Length == 0 implies that this is not user NV data storage.
//
if (strcmp (FieldName, "Year") == 0) {
//
// Write ID (offset), ID, and size
//
WriteWord (mNvDataStructSize + mNonNvDataStructSize + 0);
if (WriteLength) {
WriteByte (0, 0);
}
} else if (strcmp (FieldName, "Month") == 0) {
//
// Write ID (offset), ID, and size
//
WriteWord (mNvDataStructSize + mNonNvDataStructSize + 2);
if (WriteLength) {
WriteByte (0, 0);
}
} else if (strcmp (FieldName, "Day") == 0) {
//
// Write ID (offset), ID, and size
//
WriteWord (mNvDataStructSize + mNonNvDataStructSize + 4);
if (WriteLength) {
WriteByte (0, 0);
}
} else {
PrintErrorMessage (LineNum1, FieldName, "expected valid field name TheYear/TheMonth/TheDay");
}
return;
} else if (strcmp (StructName, "Time") == 0) {
//
// Someone specified Time.Hours|Minutes|Seconds
// BUGBUG -- define some constants for the IDs used here
//
if (strcmp (FieldName, "Hours") == 0) {
//
// Write ID (offset), ID, and size
//
WriteWord (mNvDataStructSize + mNonNvDataStructSize + 6);
if (WriteLength) {
WriteByte (0, 0);
}
} else if (strcmp (FieldName, "Minutes") == 0) {
//
// Write ID (offset), ID, and size
//
WriteWord (mNvDataStructSize + mNonNvDataStructSize + 8);
if (WriteLength) {
WriteByte (0, 0);
}
} else if (strcmp (FieldName, "Seconds") == 0) {
//
// Write ID (offset), ID, and size
//
WriteWord (mNvDataStructSize + mNonNvDataStructSize + 10);
if (WriteLength) {
WriteByte (0, 0);
}
} else {
PrintErrorMessage (LineNum1, FieldName, "expected valid field name Hours/Minutes/Seconds");
}
return;
} else {
PrintErrorMessage (LineNum1, StructName, "undefined structure");
return;
}
}
VOID
EfiVfrParser::StartStructDefinition (
INT32 IsNonNV,
INT32 LineNum
)
/*++
Routine Description:
Called when we encounter a new "struct _MY_STRUCT..." statement while parsing.
Initialize internal data and structures for parsing the fields of the structure.
Arguments:
LineNum - line number in the source file (for error reporting purposes)
IsNonNv - flag indicating (if nonzero) that the variable referred to is not in
the standard NV store.
Returns:
None
--*/
{
STRUCT_DEFINITION *StructDef;
//
// Allocate memory for the structure record
//
StructDef = (STRUCT_DEFINITION *)malloc (sizeof (STRUCT_DEFINITION));
memset (StructDef, 0, sizeof (STRUCT_DEFINITION));
StructDef->LineNum = LineNum;
//
// Set flag indicating non-NV data structure or not
//
StructDef->IsNonNV = IsNonNV;
//
// Add it to the end of our linked list. If it's the first one
// defined, then it's the default varstore ID, so set it valid.
//
if (mFirstStructDefinition == NULL) {
mFirstStructDefinition = StructDef;
StructDef->VarStoreIdValid = 1;
} else {
mLastStructDefinition->Next = StructDef;
}
mLastStructDefinition = StructDef;
}
VOID
EfiVfrParser::EndStructDefinition (
CHAR8 *StructName,
INT32 LineNum
)
{
STRUCT_DEFINITION *StructDef;
STRUCT_FIELD_DEFINITION *FieldDef;
UINT32 Offset;
//
// Make sure they have not already defined a structure with this name
//
for (StructDef = mFirstStructDefinition; StructDef != NULL; StructDef = StructDef->Next) {
if ((StructDef->Name != NULL) && (strcmp (StructDef->Name, StructName) == 0)) {
PrintErrorMessage (LineNum, StructName, "structure with this name already defined");
//
// Fall through and fill in the rest of the structure information. We do
// this because the structure has already been added to our global list,
// so will be used elsewhere, so we want it to contain valid fields.
//
}
}
//
// Allocate memory for the structure name
//
mLastStructDefinition->Name = (char *)malloc (strlen (StructName) + 1);
strcpy (mLastStructDefinition->Name, StructName);
//
// Compute the structure size, and the offsets to each field
//
Offset = 0;
for (FieldDef = mLastStructDefinition->Field; FieldDef != NULL; FieldDef = FieldDef->Next) {
FieldDef->Offset = Offset;
Offset += FieldDef->ArrayLength * FieldDef->DataSize;
}
mLastStructDefinition->Size = Offset;
//
// Go through all the structure we have so far and figure out (if we can)
// the size of the non-NV storage. We also assume that the first structure
// definition is the primary/default storage for the VFR form.
//
if (mNonNvDataStructSize == 0) {
for (StructDef = mFirstStructDefinition; StructDef != NULL; StructDef = StructDef->Next) {
if (StructDef->IsNonNV) {
mNonNvDataStructSize = StructDef->Size;
break;
}
}
}
if (mNvDataStructSize == 0) {
for (StructDef = mFirstStructDefinition; StructDef != NULL; StructDef = StructDef->Next) {
if (StructDef->IsNonNV == 0) {
mNvDataStructSize = StructDef->Size;
break;
}
}
}
}
VOID
EfiVfrParser::AddStructField (
CHAR8 *FieldName,
INT32 LineNum,
INT32 DataSize,
INT32 ArrayLength,
INT8 IsArray
)
/*++
Routine Description:
We're parsing the VFR structure definition. Add another defined field to
our definition.
Arguments:
FieldName - name of the field in the structure.
LineNum - the line number from the input (preprocessor output) file
DataSize - the size of the field (1, 2, or 4 bytes)
ArrayLength - the number of elements (for array)
IsArray - non-zero if the field is an array
Returns:
None.
--*/
{
STRUCT_FIELD_DEFINITION *FieldDef;
STRUCT_FIELD_DEFINITION *Temp;
//
// Make sure we don't already have a field of this name in our structure
//
for (FieldDef = mLastStructDefinition->Field; FieldDef != NULL; FieldDef = FieldDef->Next) {
if (strcmp (FieldDef->Name, FieldName) == 0) {
PrintErrorMessage (LineNum, FieldName, "field with this name already defined");
return;
}
}
//
// If it's an array, then they better not have a size of 0. For example:
// UINT8 MyBytes[0];
//
if (IsArray && (ArrayLength <= 0)) {
PrintErrorMessage (LineNum, FieldName, "invalid array size");
return;
}
//
// Allocate memory for a new structure field definition
//
FieldDef = (STRUCT_FIELD_DEFINITION *)malloc (sizeof (STRUCT_FIELD_DEFINITION));
memset ((char *)FieldDef, 0, sizeof (STRUCT_FIELD_DEFINITION));
FieldDef->ArrayLength = ArrayLength;
FieldDef->DataSize = DataSize;
FieldDef->IsArray = IsArray;
FieldDef->Name = (char *)malloc (strlen (FieldName) + 1);
strcpy (FieldDef->Name, FieldName);
//
// Add it to the end of the field list for the currently active structure
//
if (mLastStructDefinition->Field == NULL) {
mLastStructDefinition->Field = FieldDef;
} else {
mLastStructDefinition->LastField->Next = FieldDef;
}
mLastStructDefinition->LastField = FieldDef;
}
VOID
EfiVfrParser::AddVarStore (
CHAR8 *StructName, // actual name of the structure
CHAR8 *VarName, // actual NV variable name
UINT16 VarStoreId, // key value
INT32 LineNum // parse line number (for error reporting)
)
/*++
Routine Description:
Called while parsing a varstore statement. Add the variable store
to our linked list.
Arguments:
StructName - the name of the typedef'ed structure to use
VarName - the NV variable name as specified in the varstore statement
VarStoreId - the variable store ID as specified in the varstore statememt
LineNum - the line number from the input (preprocessor output) file
Returns:
None.
--*/
{
STRUCT_DEFINITION *StructDef;
UINT16_LIST *L16Ptr;
//
// Go through our list of previously-defined variable store IDs and
// make sure this one is not a duplicate in name or key value.
//
for (L16Ptr = mDefinedVarStoreId; L16Ptr != NULL; L16Ptr = L16Ptr->Next) {
if (L16Ptr->Value == VarStoreId) {
PrintErrorMessage (LineNum, "variable storage key already used", NULL);
PrintErrorMessage (L16Ptr->LineNum, "previous usage of storage key", NULL);
}
}
//
// Key value of 0 is invalid since that's assigned by default to the default
// variable store (the first structure parsed).
//
if (VarStoreId == 0) {
PrintErrorMessage (LineNum, "variable storage key of 0 is invalid", NULL);
}
//
// Create a new element to add to the list
//
L16Ptr = (UINT16_LIST *)malloc(sizeof (UINT16_LIST));
memset (L16Ptr, 0, sizeof (UINT16_LIST));
L16Ptr->LineNum = LineNum;
L16Ptr->Value = VarStoreId;
if (mDefinedVarStoreId == NULL) {
mDefinedVarStoreId = L16Ptr;
} else {
mLastDefinedVarStoreId->Next = L16Ptr;
}
mLastDefinedVarStoreId = L16Ptr;
//
// Find the structure definition with this name
//
for (StructDef = mFirstStructDefinition; StructDef != NULL; StructDef = StructDef->Next) {
if (strcmp (StructDef->Name, StructName) == 0) {
//
// Make sure they did not already define a variable storage ID
// for this structure.
//
if (StructDef->VarStoreId != 0) {
PrintErrorMessage (LineNum, StructName, "variable storage already defined for this structure");
PrintErrorMessage (StructDef->VarStoreLineNum, StructName, "previous definition for variable storage");
}
StructDef->VarStoreId = VarStoreId;
StructDef->VarStoreIdValid = 1;
StructDef->VarStoreLineNum = LineNum;
WriteWord (StructDef->Size);
while (*VarName) {
WriteByte(*VarName, 0);
VarName++;
}
WriteByte(0,0);
return;
}
}
PrintErrorMessage (LineNum, StructName, "structure with this name not defined");
}
VOID
EfiVfrParser::WriteDWord (
UINT32 Value,
UINT8 KeyByte
)
/*++
Routine Description:
During parsing, we came upon some code that requires a 32-bit value be
written to the VFR binary file. Queue up the 4 bytes.
Arguments:
Value - the 32-bit value to write
KeyByte - a single character which gets written out beside the first byte.
This is used to tag the data in the output file so that during
debug you have an idea what the value is.
Returns:
None.
--*/
{
//
// Write 4 bytes, little endian. Specify a key byte only on the first one
//
mOpcodeHandler.AddByte ((UINT8)Value, KeyByte);
Value \>>= 8;
mOpcodeHandler.AddByte ((UINT8)Value, 0);
Value \>>= 8;
mOpcodeHandler.AddByte ((UINT8)Value, 0);
Value \>>= 8;
mOpcodeHandler.AddByte ((UINT8)Value, 0);
}
VOID
EfiVfrParser::WriteOpByte (
UINT32 LineNum,
UINT8 ByteValue
)
/*++
Routine Description:
During parsing, we came upon a new VFR opcode. At this point we flush
the output queue and then queue up this byte (with 'O' for opcode tag).
Arguments:
ByteValue - opcode value
Returns:
None.
--*/
{
mOpcodeHandler.AddOpcodeByte (ByteValue, LineNum);
}
VOID
EfiVfrParser::WriteByte (
UINT8 ByteValue,
UINT8 Key
)
/*++
Routine Description:
During parsing of the VFR we spoonfeed this function with bytes to write to
the output VFR binary file. This function simply queues up the bytes, and
the queue gets flushed each time a new VFR opcode is encountered.
Arguments:
ByteValue - raw byte to write
Key - character to tag the byte with when we write ByteValue to the
output file.
Returns:
None.
--*/
{
mOpcodeHandler.AddByte (ByteValue, Key);
}
VOID
EfiVfrParser::WriteWord (
UINT32 Value
)
/*++
Routine Description:
During VFR parsing we came upon a case where we need to write out a
16-bit value. Queue it up.
Arguments:
Value - value to write.
Returns:
None.
--*/
{
mOpcodeHandler.AddByte ((UINT8)Value, 0);
mOpcodeHandler.AddByte ((UINT8)((Value \>> 8) & 0xFF), 0);
}
VOID
EfiVfrParser::WriteStringIdWord (
UINT16 WordValue
)
{
mOpcodeHandler.AddByte ((UINT8)WordValue, 'S');
mOpcodeHandler.AddByte ((UINT8)((WordValue \>> 8) & 0xFF), 0);
}
VOID
EfiVfrParser::FreeGotoReferences ()
/*++
Routine Description:
Called during cleanup to free up the memory we allocated when
keeping track of VFR goto statements.
Arguments:
None
Returns:
None
--*/
{
GOTO_REFERENCE *CurrRef;
GOTO_REFERENCE *NextRef;
FORM_ID_VALUE *CurrFormId;
FORM_ID_VALUE *NextFormId;
UINT8 Found;
CHAR8 Name[20];
//
// Go through all the "goto" references and make sure there was a
// form ID of that value defined.
//
for (CurrRef = mGotoReferences; CurrRef != NULL; CurrRef = CurrRef->Next) {
Found = 0;
for (CurrFormId = mFormIdValues; CurrFormId != NULL; CurrFormId = CurrFormId->Next) {
if (CurrRef->Value == CurrFormId->Value) {
Found = 1;
break;
}
}
if (!Found) {
sprintf (Name, "%d", (UINT32)CurrRef->Value);
PrintErrorMessage (CurrRef->RefLineNum, Name, "undefined form ID");
}
}
//
// Now free up the form id and goto references
//
CurrFormId = mFormIdValues;
while (CurrFormId != NULL) {
NextFormId = CurrFormId->Next;
free (CurrFormId);
CurrFormId = NextFormId;
}
mFormIdValues = NULL;
CurrRef = mGotoReferences;
while (CurrRef != NULL) {
NextRef = CurrRef->Next;
free (CurrRef);
CurrRef = NextRef;
}
mGotoReferences = NULL;
}
VOID
EfiVfrParser::AddGotoReference (
UINT32 GotoNumber,
UINT32 LineNum
)
/*++
Routine Description:
During VFR parsing we came upon a goto statement. Since we support
forward references, save the referenced label and at the end of parsing
we'll check that the label was actually defined somewhere.
Arguments:
GotoNumber - the label number referenced
LineNum - the line number where the reference was made (used for
error reporting)
Returns:
None
--*/
{
GOTO_REFERENCE *NewRef;
NewRef = (GOTO_REFERENCE *)malloc (sizeof (GOTO_REFERENCE));
if (NewRef == NULL) {
Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");
return;
}
memset ((char *)NewRef, 0, sizeof (GOTO_REFERENCE));
NewRef->Value = (UINT16)GotoNumber;
NewRef->RefLineNum = LineNum;
NewRef->Next = mGotoReferences;
mGotoReferences = NewRef;
}
VOID
EfiVfrParser::AddFormId (
INT32 FormIdValue,
UINT32 LineNum
)
/*++
Routine Description:
This function is called when we parse "form formid = 3" statements.
We save the form ID valud so we can verify that duplicates are not
defined. Also, these are the targets of goto statements, so when we're
done parsing the script we also go through all the goto statements to
check that there was a target FormId defined as referenced by each
goto statement.
Note that formid = 0 is invalid.
Arguments:
FormIdValue - the parsed value for the Form ID
LineNum - line number of the source file we're parsing
Returns:
NA
--*/
{
FORM_ID_VALUE *NewFormId;
char *FileName;
char *FileName2;
UINT32 LineNum2;
//
// Verify that FormId != 0
//
if (FormIdValue == 0) {
FileName = ConvertLineNumber (&LineNum);
Error (FileName, LineNum, 0, "form ID cannot be 0", NULL);
return;
}
//
// First go through all previously defined form IDs and make sure they have not defined
// duplicates.
//
for (NewFormId = mFormIdValues; NewFormId != NULL; NewFormId = NewFormId->Next) {
if ((UINT16)FormIdValue == NewFormId->Value) {
FileName = ConvertLineNumber (&LineNum);
LineNum2 = NewFormId->LineNum;
FileName2 = ConvertLineNumber (&LineNum2);
Error (FileName, LineNum, 0, NULL, "form ID %d already defined", FormIdValue);
Error (FileName2, LineNum2, 0, NULL, "form ID %d previous definition", FormIdValue);
return;
}
}
//
// Allocate memory for a new one
//
NewFormId = (FORM_ID_VALUE *)malloc (sizeof (FORM_ID_VALUE));
if (NewFormId == NULL) {
Error (PROGRAM_NAME, 0, 0, NULL, "memory allocation failure");
return;
}
memset ((char *)NewFormId, 0, sizeof (FORM_ID_VALUE));
NewFormId->LineNum = LineNum;
NewFormId->Next = mFormIdValues;
NewFormId->Value = (UINT16)FormIdValue;
mFormIdValues = NewFormId;
}
UINT32
EfiVfrParser::GetNumber (
CHAR8 *NumStr,
UINT32 LineNum,
UINT32 NumBytes
)
{
UINT32 Value;
if ((NumStr[0] == '0') && (NumStr[1] == 'x')) {
AtoX (NumStr + 2, 4, &Value);
} else {
Value = (UINT32)atoi (NumStr);
}
//
// Check range
//
if ((NumBytes < 4) && (Value & ((UINT32)0xFFFFFFFF << (NumBytes * 8)))) {
PrintErrorMessage (LineNum, NumStr, "value out of range");
return 0;
}
return Value;
}
>>
} // end grammar class