Comment créer un parsingur syntaxique (lex / yacc)?

J’ai le fichier suivant et qui doit être analysé

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

Les lignes commencent par -- seront traitées comme des lignes de commentaires. et le fichier commence ‘Start’ et se termine par end . La chaîne après Start est l’ UserID , puis le name et l’ address seront à l’intérieur des guillemets doubles.

J’ai besoin d’parsingr le fichier et d’écrire les données analysées dans un fichier XML.

Donc, le fichier résultant sera comme

   

J’utilise maintenant la recherche de motif ( Regular Expressions ) pour parsingr le fichier ci-dessus. Voici mon exemple de code.

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

Méthode : 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éthode : FormateRowData

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

Méthode : 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éthode : WriteFile

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

j’ai entendu parler de ParserGenerator

S’il vous plaît, aidez-moi à écrire un parsingur syntaxique en utilisant Lex et Yacc. La raison en est que mon parsingur existant ( Pattern Matching ) n’est pas flexible, mais plutôt qu’il n’est pas correct (je pense que oui).

Comment utiliser le ParserGenerator (J’ai lu l’ exemple de projet de code 1 et l’ exemple de projet de code 2, mais je ne connais pas encore cela). S’il vous plaît, suggérez-moi un générateur d’parsingur qui génère des parsingurs C #.

Gardens Point LEX et le générateur d’parsingur Gardens Point sont fortement influencés par LEX et YACC et produisent du code C #.

Votre grammaire est assez simple pour que je pense que votre approche actuelle convient, mais je tiens à vous féliciter de vouloir apprendre la “vraie” façon de le faire. 🙂 Voici donc ma suggestion pour une grammaire (juste les règles de production; c’est loin d’être un exemple complet. Le fichier GPPG doit remplacer le ... par le code C # pour construire l’arbre de syntaxe, et vous avez besoin de déclarations de jetons, etc. Lisez les exemples de GPPG dans la documentation et vous aurez également besoin du fichier GPLEX décrivant les jetons):

 /* 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 ssortingng "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 parsings 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) QuotedSsortingng { ... } 

Vous devrez d’abord définir la grammaire de votre parsingur. (Partie Yacc)

Semble aimer être quelque chose comme:

 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 

L’parsing lexicale sera effectuée lex. Et je suppose que votre regex sera utile pour les définir.

Ma réponse est un brouillon, je vous conseille de chercher sur Internet un didacticiel plus complet sur lex / yacc flex / bison et de revenir ici si vous avez un problème plus ciblé.

Je ne sais pas non plus s’il existe une implémentation C # qui vous permettrait de conserver un code géré. Vous devrez peut-être utiliser une importation C / C ++ non gérée.