mirror of https://github.com/acidanthera/audk.git
3530 lines
114 KiB
Plaintext
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
|
|
|