¿Cómo crear un analizador (lex / yacc)?

Tengo el siguiente archivo y necesito ser analizado

--TestFile Start ASDF123 Name "John" Address "#6,US" end ASDF123 

Las líneas comienzan con -- serán tratadas como líneas de comentario. y el archivo comienza ‘Inicio’ y termina con end . La cadena después de Start es el UserID y, a continuación, el name y la address estarán dentro de los espacios dobles.

Necesito analizar el archivo y escribir los datos analizados en un archivo xml.

Así que el archivo resultante será como

   

ahora estoy usando la coincidencia de patrones ( Regular Expressions ) para analizar el archivo anterior. Aquí está mi código de muestra.

  ///  /// To Store the row data from the file ///  List MyList = new List(); String strName = ""; String strAddress = ""; String strInfo = ""; 

Método : ReadFile

  ///  /// To read the file into a List ///  private void ReadFile() { StreamReader Reader = new StreamReader(Application.StartupPath + "\\TestFile.txt"); while (!Reader.EndOfStream) { MyList.Add(Reader.ReadLine()); } Reader.Close(); } 

Método : FormateRowData

  ///  /// To remove comments ///  private void FormateRowData() { MyList = MyList.Where(X => X != "").Where(X => X.StartsWith("--")==false ).ToList(); } 

Método : ParseData

  ///  /// To Parse the data from the List ///  private void ParseData() { Match l_mMatch; Regex RegData = new Regex("start[ \t\r\n]*(?[a-z0-9]*)", RegexOptions.IgnoreCase); Regex RegName = new Regex("name [ \t\r\n]*\"(?[az]*)\"", RegexOptions.IgnoreCase); Regex RegAddress = new Regex("address [ \t\r\n]*\"(?
[a-z0-9 #,]*)\"", RegexOptions.IgnoreCase); for (int Index = 0; Index < MyList.Count; Index++) { l_mMatch = RegData.Match(MyList[Index]); if (l_mMatch.Success) strInfo = l_mMatch.Groups["Data"].Value; l_mMatch = RegName.Match(MyList[Index]); if (l_mMatch.Success) strName = l_mMatch.Groups["Name"].Value; l_mMatch = RegAddress.Match(MyList[Index]); if (l_mMatch.Success) strAddress = l_mMatch.Groups["Address"].Value; } }

Método : WriteFile

  ///  /// To write parsed information into file. ///  private void WriteFile() { XDocument XD = new XDocument( new XElement(strInfo, new XElement("Name", new XAttribute("Value", strName)), new XElement("Address", new XAttribute("Value", strAddress)))); XD.Save(Application.StartupPath + "\\File.xml"); } 

He oído hablar de ParserGenerator

Por favor, ayúdame a escribir un analizador usando lex y yacc. La razón de esto es que mi analizador exsisting ( Pattern Matching ) no es flexible, por lo que no es la forma correcta (creo que sí).

Cómo hago uso de ParserGenerator (leí Code Project Sample One y Code Project Sample Two pero todavía no estoy familiarizado con esto). Por favor, sugiérame un generador de analizador que genere analizadores de C #.

Gardens Point LEX y el generador de analizador de Gardens Point están fuertemente influenciados por LEX y YACC, y el código C # de salida.

Tu gramática es lo suficientemente simple, por lo que creo que tu enfoque actual está bien, pero felicitaciones por querer aprender la forma “real” de hacerlo. 🙂 Aquí está mi sugerencia para una gramática (solo las reglas de producción; esto dista mucho de ser un ejemplo completo. El archivo GPPG real necesita reemplazar el código ... por el código C # para crear el árbol de syntax, y necesita declaraciones de token, etc. . – lea los ejemplos de GPPG en la documentación. Y también necesita el archivo GPLEX que describe los tokens):

 /* Your input file is a list of "top level elements" */ TopLevel : TopLevel TopLevelElement { ... } | /* (empty) */ /* A top level element is either a comment or a block. The COMMENT token must be described in the GPLEX file as any line that starts with -- . */ TopLevelElement: Block { ... } | COMMENT { ... } /* A block starts with the token START (which, in the GPLEX file, is defined as the string "Start"), continues with some identifier (the block name), then has a list of elements, and finally the token END followed by an identifier. If you want to validate that the END identifier is the same as the START identifier, you can do that in the C# code that analyses the syntax tree built by GPPG. The token Identifier is also defined with a regular expression in GPLEX. */ Block: START Identifier BlockElementList END Identifier { ... } BlockElementList: BlockElementList BlockElement { ... } | /* empty */ BlockElement: (NAME | ADDRESS) QuotedString { ... } 

Primero tendrás que definir la gramática de tu analizador. (Yacc parte)

Parece ser algo como:

 file : record file ; record: start identifier recordContent end identifier {//rule to match the two identifiers} ; recordContent: name value; //Can be more detailed if you require order in the fields 

El análisis léxico se realizará mediante lex. Y supongo que su expresión regular será útil para definirlos.

Mi respuesta es un borrador, le aconsejo que busque en internet para encontrar un tutorial más completo sobre lex / yacc flex / bison, y regrese aquí si tiene un problema más específico.

Tampoco sé si hay una implementación de C # que le permita mantener un código administrado. Es posible que tenga que usar la importación de C / C ++ no administrada.