| /*++ | |
| 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.VfrFileName, "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 | |