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