Пример #1
0
        public string ConvertAst(Node headNode)
        {
            var builder = new StringBuilder();

            ConvertNode(headNode, builder);

            return builder.ToString();
        }
Пример #2
0
 private void AddNodeText(Node node, StringBuilder builder, string prefix)
 {
     var prefixChar = 'a';
     var colour = node.IsTerminal ? " fillcolor=\"gold\" style=\"filled\"" : "";
     builder.AppendLine($"  {prefix} [label=\"{node.Contents}\"{colour}]");
     foreach (var child in node.Children)//.Where(child => !child.Contents.Contains("Null")))
     {
         builder.AppendLine($"  {prefix} -> {prefix}{prefixChar}");
         AddNodeText(child, builder, prefix + prefixChar);
         prefixChar ++;
     }
 }
Пример #3
0
        public string GenerateGraphString(Node headNode)
        {
            var builder = new StringBuilder("digraph G {");
            builder.AppendLine("  a ;");
            AddNodeText(
                node: headNode, 
                builder: builder, 
                prefix: "a");

            builder.AppendLine("}");

            return builder.ToString();
        }
Пример #4
0
 public Node AddChild(Node child)
 {
     _children.Add(child);
     return this;
 }
Пример #5
0
        /// <summary>
        /// Adds the following grammar rules to the RDP parser passed into the function:
        /// 
        /// base        -> stmt
        /// stmt        -> IF expr THEN stmt ELSE stmt
        ///              | WHILE expr DO stmt
        ///              | INPUT ID
        ///              | ID ASSIGN expr
        ///              | WRITE expr
        ///              | BEGIN stmtlist END
        /// stmtlist    -> stmt SEMICOLON stmtlist'
        /// stmtlist'   -> stmt SEMICOLON stmtlist'
        ///              | .
        /// expr        -> term expr'
        /// expr'       -> addop term expr'
        ///              | .
        /// term        -> factor term'
        /// term'       -> mulop factor term'
        ///              | .
        /// factor      -> LPAR expr RPAR
        ///              | ID
        ///              | NUM
        ///              | SUB NUM
        /// addop       -> ADD | SUB
        /// mulop       -> MUL | DIV
        /// </summary>
        /// <param name="parser">Parser that should accept the rules</param>
        public static void AddRdpRules(RecursiveDescentParser parser)
        {
            // base -> stmt
            parser.AddRule(
                name: "base",
                decider: rdp => true,
                evaluator: rdp => rdp.InvokeRule("stmt"));

            // stmt -> IF expr THEN stmt ELSE stmt
            parser.AddRule( // if
                name: "stmt",
                decider: rdp => rdp.TryMatch(TokenType.If),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "IF Statement", Type = NodeType.If};
                    node.AddChild(rdp.TryConsumeToken(TokenType.If));
                    node.AddChild(rdp.InvokeRule("expr"));
                    node.AddChild(rdp.TryConsumeToken(TokenType.Then));
                    node.AddChild(rdp.InvokeRule("stmt"));
                    node.AddChild(rdp.TryConsumeToken(TokenType.Else));
                    node.AddChild(rdp.InvokeRule("stmt"));
                    return node;
                });

            //  stmt -> WHILE expr DO stmt
            parser.AddRule( // while
                name: "stmt",
                decider: rdp => rdp.TryMatch(TokenType.While),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "WHILE Statement", Type = NodeType.While};
                    node.AddChild(rdp.TryConsumeToken(TokenType.While));
                    node.AddChild(rdp.InvokeRule("expr"));
                    node.AddChild(rdp.TryConsumeToken(TokenType.Do));
                    node.AddChild(rdp.InvokeRule("stmt"));
                    return node;
                });

            // stmt -> INPUT ID
            parser.AddRule( // input
                name: "stmt",
                decider: rpd => rpd.TryMatch(TokenType.Input),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "INPUT Statement", Type = NodeType.Input};
                    node.AddChild(rdp.TryConsumeToken(TokenType.Input));
                    node.AddChild(rdp.TryConsumeToken(TokenType.Id));
                    return node;
                });

            // stmt -> ID ASS expr
            parser.AddRule( // assign
                name: "stmt",
                decider: rdp => rdp.TryMatch(TokenType.Id),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "Assign Statement", Type = NodeType.Assign};
                    node.AddChild(rdp.TryConsumeToken(TokenType.Id));
                    node.AddChild(rdp.TryConsumeToken(TokenType.Assign));
                    node.AddChild(rdp.InvokeRule("expr"));
                    return node;
                });

            // stmt -> WRITE expr
            parser.AddRule( // write
                name: "stmt",
                decider: rdp => rdp.TryMatch(TokenType.Write),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "WRITE Statement", Type = NodeType.Write};
                    node.AddChild(rdp.TryConsumeToken(TokenType.Write));
                    node.AddChild(rdp.InvokeRule("expr"));
                    return node;
                });

            // stmt -> BEGIN stmtlist END
            parser.AddRule( // begin
                name: "stmt",
                decider: rdp => rdp.TryMatch(TokenType.Begin),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "BEGIN Statement", Type = NodeType.Begin};
                    node.AddChild(rdp.TryConsumeToken(TokenType.Begin));
                    node.AddChild(rdp.InvokeRule("stmtlist"));
                    node.AddChild(rdp.TryConsumeToken(TokenType.End));
                    return node;
                });

            // stmtlist -> stmt SEMICOLON stmtlist'
            parser.AddRule(
                name: "stmtlist",
                decider: rdp => rdp.TryMatch("stmt"),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "Statement List", Type = NodeType.StatementList};
                    node.AddChild(rdp.InvokeRule("stmt"));
                    node.AddChild(rdp.TryConsumeToken(TokenType.Semicolon));
                    node.AddChild(rdp.InvokeRule("stmtlist'"));
                    return node;
                });

            // Transformed rule
            // stmtlist' -> stmt SEMICOLON stmtlist'
            parser.AddRule(
                name: "stmtlist'",
                decider: rdp => rdp.TryMatch("stmt"),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "Statement List", Type = NodeType.MoreStatements};
                    
                    node.AddChild(rdp.InvokeRule("stmt"));
                    node.AddChild(rdp.TryConsumeToken(TokenType.Semicolon));
                    node.AddChild(rdp.InvokeRule("stmtlist'"));
                    return node;
                });

            // Transformed rule
            // stmtlist' -> .
            parser.AddRule(
                name: "stmtlist'",
                decider: rdp => !rdp.TryMatch("stmt"),
                evaluator: rdp => new Node {Contents = "Null Statement", Type = NodeType.Null});

            // expr -> term expr'
            parser.AddRule(
                name: "expr",
                decider: rdp => rdp.TryMatch("term"),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "Expr Statement", Type = NodeType.Expression};
                    node.AddChild(rdp.InvokeRule("term"));
                    node.AddChild(rdp.InvokeRule("expr'"));
                    return node;
                });

            // Transformed rule
            // expr' -> addop term expr'
            parser.AddRule(
                name: "expr'",
                decider: rdp => rdp.TryMatch("addop"),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "Expr' Statement", Type = NodeType.MoreExpression};
                    node.AddChild(rdp.InvokeRule("addop"));
                    node.AddChild(rdp.InvokeRule("term"));
                    node.AddChild(rdp.InvokeRule("expr'"));
                    return node;
                });

            // Transformed rule
            // expr' -> .
            parser.AddRule(
                name: "expr'",
                decider: rdp => !rdp.TryMatch("addop"),
                evaluator: rdp => new Node {Contents = "Null expr", Type = NodeType.Null});

            // term -> factor term'
            parser.AddRule(
                name: "term",
                decider: rdp => rdp.TryMatch("factor"),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "Term statement", Type = NodeType.Term};
                    node.AddChild(rdp.InvokeRule("factor"));
                    node.AddChild(rdp.InvokeRule("term'"));
                    return node;
                });

            // Transformed rule
            // term' -> mulop factor term'
            parser.AddRule(
                name: "term'",
                decider: rdp => rdp.TryMatch("mulop"),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "Term' statement", Type = NodeType.MoreTerms};
                    node.AddChild(rdp.InvokeRule("mulop"));
                    node.AddChild(rdp.InvokeRule("factor"));
                    node.AddChild(rdp.InvokeRule("term'"));
                    return node;
                });

            // Transformed rule
            // term' -> .
            parser.AddRule(
                name: "term'",
                decider: rdp => !rdp.TryMatch("mulop"),
                evaluator: rdp => new Node {Contents = "Null term", Type = NodeType.Null});

            // mulop -> MUL
            parser.AddRule(
                name: "mulop",
                decider: rdp => rdp.TryMatch(TokenType.Mul),
                evaluator: rdp => rdp.TryConsumeToken(TokenType.Mul));

            // mulop -> DIV
            parser.AddRule(
                name: "mulop",
                decider: rdp => rdp.TryMatch(TokenType.Div),
                evaluator: rdp => rdp.TryConsumeToken(TokenType.Div));

            // addop -> ADD
            parser.AddRule(
                name: "addop",
                decider: rdp => rdp.TryMatch(TokenType.Add),
                evaluator: rdp => rdp.TryConsumeToken(TokenType.Add));

            // addop -> SUB
            parser.AddRule(
                name: "addop",
                decider: rdp => rdp.TryMatch(TokenType.Sub),
                evaluator: rdp => rdp.TryConsumeToken(TokenType.Sub));

            // factor -> LPAR expr RPAR
            parser.AddRule(
                name: "factor",
                decider: rdp => rdp.TryMatch(TokenType.LPar),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "Factor statement", Type = NodeType.Factor};
                    node.AddChild(rdp.TryConsumeToken(TokenType.LPar));
                    node.AddChild(rdp.InvokeRule("expr"));
                    node.AddChild(rdp.TryConsumeToken(TokenType.RPar));
                    return node;
                });

            // factor -> ID
            parser.AddRule(
                name: "factor",
                decider: rdp => rdp.TryMatch(TokenType.Id),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "Factor statement", Type = NodeType.Factor};
                    node.AddChild(rdp.TryConsumeToken(TokenType.Id));
                    return node;
                });

            // factor -> NUM
            parser.AddRule(
                name: "factor",
                decider: rdp => rdp.TryMatch(TokenType.Num),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "Factor statement", Type = NodeType.Factor};
                    node.AddChild(rdp.TryConsumeToken(TokenType.Num));
                    return node;
                });

            // factor -> SUB NUM
            parser.AddRule(
                name: "factor",
                decider: rdp => rdp.TryMatch(TokenType.Sub),
                evaluator: rdp =>
                {
                    var node = new Node {Contents = "Factor statement", Type = NodeType.Factor};
                    node.AddChild(rdp.TryConsumeToken(TokenType.Sub));
                    node.AddChild(rdp.TryConsumeToken(TokenType.Num));
                    return node;
                });
        }
Пример #6
0
 private void ProcessFactor(Node node, StringBuilder builder)
 {
     switch (node.Children.Count)
     {
         case 3:
             ConvertNode(node.Children[1], builder);
             break;
         case 2:
             // [-] [num]
             builder.AppendLine($"    cPUSH -{node.Children[1].Data}");
             break;
         default:
             builder.AppendLine(node.Children[0].TerminalTokenType == TokenType.Id
                 ? $"    rPUSH {node.Children[0].Data}"
                 : $"    cPUSH {node.Children[0].Data}");
             break;
     }
 }
Пример #7
0
 private void ConvertNode(Node node, StringBuilder builder)
 {
     switch (node.Type)
     {
         case NodeType.If:
             ProcessIf(node, builder);
             break;
         case NodeType.Begin:
             // of the form [BEGIN] [statement list] [END]
             ConvertNode(node.Children[1], builder);
             break;
         case NodeType.While:
             ProcessWhile(node, builder);
             break;
         case NodeType.Factor:
             ProcessFactor(node, builder);
             break;
         case NodeType.Expression:
         case NodeType.Term: // has the form [term] [expr']
             ConvertNode(node.Children[0], builder);
             ConvertNode(node.Children[1], builder);
             break;
         case NodeType.StatementList:
             // has the form [stmt] [;] [stmtlist']
             ConvertNode(node.Children[0], builder);
             ConvertNode(node.Children[2], builder);
             break;
         case NodeType.MoreExpression:
             // of the form [addop] [term] [moreexpr]
             ConvertNode(node.Children[2], builder); // more expr
             ConvertNode(node.Children[1], builder); // term
             builder.AppendLine( // postfix the add/sub
                 node.Children[0].TerminalTokenType == TokenType.Add ?
                 "    OP2 +" : "    OP2 -");
             break;
         case NodeType.MoreTerms:
             // of the form [mulop] [factor] [moreterm]
             ConvertNode(node.Children[2], builder); // more expr
             ConvertNode(node.Children[1], builder); // term
             builder.AppendLine( // postfix the add/sub
                 node.Children[0].TerminalTokenType == TokenType.Mul ?
                 "    OP2 *" : "    OP2 /");
             // has the form 
             break;
         case NodeType.Terminal: // may not be needed
             break;
         case NodeType.Null: // nothing to add
             break;
         case NodeType.Input:
             // of the form [INPUT] [ID]
             builder.AppendLine($"    READ {node.Children[1].Data}");
             break;
         case NodeType.Assign:
             // has the form [ID] [:=] [Expr]
             ConvertNode(node.Children[2], builder);
             builder.AppendLine($"    LOAD {node.Children[0].Data}");
             break;
         case NodeType.Write:
             // of the form [WRITE] [expr]
             ConvertNode(node.Children[1], builder);
             builder.AppendLine("    PRINT");
             break;
         case NodeType.MoreStatements:
             // of the form [stmt] [;] [morestmt]
             ConvertNode(node.Children[0], builder);
             ConvertNode(node.Children[2], builder);
             break;
         default:
             throw new ArgumentOutOfRangeException();
     }
 }
Пример #8
0
 private void ProcessWhile(Node headNode, StringBuilder builder)
 {
     // of the form [WHILE] [expr] [DO] [stmt]
     var headLabel = GenerateLabel();
     var exitLabel = GenerateLabel();
     // make labels first
     builder.AppendLine($"{headLabel}:");
     ConvertNode(headNode.Children[1], builder); // eval expr
     // decision branch
     builder.AppendLine($"    cJUMP {exitLabel}");
     ConvertNode(headNode.Children[3], builder); // do statement
     // skip back, and add follow label
     builder.AppendLine($"    JUMP {headLabel}");
     builder.AppendLine($"{exitLabel}:");
 }
Пример #9
0
        private void ProcessIf(Node headNode, StringBuilder builder)
        {
// of the form [IF] [expr] [THEN] [stmt] [ELSE] [stmt]
            var elseLabel = GenerateLabel();
            var skipLabel = GenerateLabel();

            ConvertNode(headNode.Children[1], builder);
            builder.AppendLine($"    cJUMP {elseLabel}");
            ConvertNode(headNode.Children[3], builder);
            builder.AppendLine($"    JUMP {skipLabel}");
            builder.AppendLine($"{elseLabel}:");
            ConvertNode(headNode.Children[5], builder);
            builder.AppendLine($"{skipLabel}:");
        }
Пример #10
0
 /// <summary>
 /// Generates the graphviz representation of the AST
 /// </summary>
 /// <param name="parentNode">root node of the AST</param>
 private static void GenerateGraphvis(Node parentNode)
 {
     Console.WriteLine("Writing to graphviz format...");
     File.WriteAllText("graphviz.dot", 
         new GraphVizGenerator().GenerateGraphString(parentNode));
 }
Пример #11
0
 /// <summary>
 /// Generates the stack machine code defined in the assignment description
 /// </summary>
 /// <param name="parentNode">Root node of the AST</param>
 private static void GenerateCompiledCode(Node parentNode)
 {
     Console.WriteLine("Writing compiled code...");
     File.WriteAllText("StackCode.txt",
         new StackMachineConverter().ConvertAst(parentNode));
 }