domingo, 7 de septiembre de 2014

Ejemplo de Gramática en Irony .NET


Al contrario que la mayoría de analizadores yacc/lex Irony no emplea generación de código para parser o scanner basado en un meta lenguaje específico.
Irony utiliza la gramática codificada como una clase c# para controlar el proceso de parsing
Aquí mostramos un ejemplo: 
using System;
using System.Collections.Generic;
using System.Text;
using Irony.Parsing;
using Irony.Ast;

namespace Irony.Samples {
  // Esta gramática describe programas que reconocen expresiones
  //simples y asignaciones
  // por Ej:
  // x = 3
  // y = -x + 5

  [Language("ExpressionEvaluator", "1.0", "Multi-line expression evaluator")]

  public class ExpressionEvaluatorGrammar : Irony.Parsing.Grammar {
    public ExpressionEvaluatorGrammar() {

      // 1. Terminales
      var number = new NumberLiteral("number");
      number.DefaultIntTypes = new TypeCode[] { TypeCode.Int32,
TypeCode.Int64, NumberLiteral.TypeCodeBigInt };
      var identifier = new IdentifierTerminal("identifier");
      var comment = new CommentTerminal("comment", "#", "\n", "\r");
      //los comentarios deben agregarse a la lista NonGrammarTerminals;
      //no se utiliza directamente en la gramática,
      // asi que debemos agregarlo para que el Scanner sepa que es
      //un terminal válido.
      base.NonGrammarTerminals.Add(comment);

      // 2. No-terminales
      var Expr = new NonTerminal("Expr");
      var Term = new NonTerminal("Term");
      var BinExpr = new NonTerminal("BinExpr", typeof(BinExprNode));
      var ParExpr = new NonTerminal("ParExpr");
      var UnExpr = new NonTerminal("UnExpr", typeof(UnExprNode));
      var UnOp = new NonTerminal("UnOp");
      var BinOp = new NonTerminal("BinOp", "operator");
      var PostFixExpr = new NonTerminal("PostFixExpr", typeof(UnExprNode));
      var PostFixOp = new NonTerminal("PostFixOp");
      var AssignmentStmt = new NonTerminal("AssignmentStmt", typeof(AssigmentNode));
      var AssignmentOp = new NonTerminal("AssignmentOp", "assignment operator");
      var Statement = new NonTerminal("Statement");
      var ProgramLine = new NonTerminal("ProgramLine");
      var Program = new NonTerminal("Program", typeof(StatementListNode));

      // 3. Reglas en formato BNF
      Expr.Rule = Term | UnExpr | BinExpr | PostFixExpr;
      Term.Rule = number | ParExpr | identifier;
      ParExpr.Rule = "(" + Expr + ")";
      UnExpr.Rule = UnOp + Term;
      UnOp.Rule = ToTerm("+") | "-" | "++" | "--";
      BinExpr.Rule = Expr + BinOp + Expr;
      BinOp.Rule = ToTerm("+") | "-" | "*" | "/" | "**";
      PostFixExpr.Rule = Term + PostFixOp;
      PostFixOp.Rule = ToTerm("++") | "--";
      AssignmentStmt.Rule = identifier + AssignmentOp + Expr;
      AssignmentOp.Rule = ToTerm("=") | "+=" | "-=" | "*=" | "/=";
      Statement.Rule = AssignmentStmt | Expr | Empty;
      ProgramLine.Rule = Statement + NewLine;
      Program.Rule = MakeStarRule(Program, ProgramLine);
      this.Root = Program;       // Se coloca la Raiz

      // 4. Precedencia de Operadores
      RegisterOperators(1, "+", "-");
      RegisterOperators(2, "*", "/");
      RegisterOperators(3, Associativity.Right, "**");

      // 5. Terminos de puntuación
      RegisterPunctuation("(", ")");
      RegisterBracePair("(", ")");
      MarkTransient(Term, Expr, Statement, BinOp, UnOp, PostFixOp,
AssignmentOp, ProgramLine, ParExpr);

      //añade automáticamente un salto de línea antes del EOF para
      //que las reglas funcionen correctamente cuando no haya salto
      //de linea al final del archivo
      this.LanguageFlags = LanguageFlags.CreateAst
| LanguageFlags.NewLineBeforeEOF | LanguageFlags.CanRunSample;
    }
  }
}//namespace

No hay comentarios:

Publicar un comentario