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