What's wrong with this code?

Mar 18, 2012 at 12:54 PM
Edited Mar 18, 2012 at 12:56 PM

Yeah, what's wrong with this code?:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Irony;
using Irony.Ast;
using Irony.Parsing;

namespace SollarScript
{
    public class SollarScriptGrammar : Grammar
    {
        public SollarScriptGrammar()
        {
            NonTerminal Program = new NonTerminal("Program");
            NonTerminal ClassDeclaration = new NonTerminal("ClassDeclaration");
            NonTerminal CodeBlock = new NonTerminal("CodeBlock");
            NonTerminal Statement = new NonTerminal("Statement");
            NonTerminal Expression = new NonTerminal("Expression");
            NonTerminal VariableDeclaration = new NonTerminal("VariableDeclaration");
            NonTerminal FunctionDeclaration = new NonTerminal("FunctionDeclaration");
            NonTerminal BinaryOp = new NonTerminal("BinaryOp");
            NonTerminal ModifierList = new NonTerminal("ModifierList");
            NonTerminal StatementList = new NonTerminal("StatementList");
            NonTerminal Type = new NonTerminal("Type");
            NonTerminal FunctionCall = new NonTerminal("FunctionCall");
            NonTerminal FunctionCallParamList = new NonTerminal("FunctionCallParamList");
            NonTerminal FunctionCallParam = new NonTerminal("FunctionCallParam");
            NonTerminal FunctionDeclarationParamList = new NonTerminal("FunctionDeclarationParamList");
            NonTerminal Return = new NonTerminal("Return");
            NonTerminal Assignment = new NonTerminal("Assignment");

            Terminal Comment = new CommentTerminal("Comment", "//", "\n");
            Terminal Identifier = new RegexBasedTerminal("Identifier", "[a-zA-Z_][a-zA-Z0-9_]*");
            Terminal Number = new RegexBasedTerminal("Number", @"\b[1-9][0-9]*\b");
            Terminal DoubleNumber = new RegexBasedTerminal("DoubleNumber", @"\b[1-9][0-9]*\.[0-9]+\b");
            Terminal String = new RegexBasedTerminal("String", string.Format(@"\{0}[^\{0}]*\{0}", "\""));
            Terminal Modifier = new RegexBasedTerminal("Modifier", @"\b(public|private|placeable)\b");
            Terminal BuiltinType = new RegexBasedTerminal("BuiltinType", @"\b(string|int|double|void|short|byte)\b");

            Program.Rule = ClassDeclaration;
            ClassDeclaration.Rule = ModifierList + "class" + Identifier + CodeBlock;
            CodeBlock.Rule = "{" + StatementList + "}";
            Statement.Rule = VariableDeclaration | FunctionDeclaration | FunctionCall | Return | Assignment;
            Expression.Rule = String | Number | Identifier | DoubleNumber | Expression + BinaryOp + Expression;
            VariableDeclaration.Rule = Type + Identifier + ";" | Type + Identifier + "=" + Expression + ";";
            FunctionDeclaration.Rule = ModifierList + Type + Identifier + "(" + FunctionDeclarationParamList + ")" + CodeBlock;
            BinaryOp.Rule = ToTerm("+") | ToTerm("-") | ToTerm("*") | ToTerm("/");
            ModifierList.Rule = MakeStarRule(ModifierList, null, Modifier);
            StatementList.Rule = MakeStarRule(StatementList, null, Statement);
            Type.Rule = BuiltinType | Identifier;
            FunctionCall.Rule = Identifier + "(" + FunctionCallParamList + ")" + ";";
            FunctionCallParam.Rule = Expression;
            FunctionCallParamList.Rule = MakeListRule(FunctionCallParamList, ToTerm(","), FunctionCallParam);
            FunctionDeclarationParamList.Rule = MakeListRule(FunctionDeclarationParamList, ToTerm(","), VariableDeclaration);
            Return.Rule = "return" + Expression + ";";
            Assignment.Rule = Identifier + "=" + Expression + ";";

            this.Root = Program;
            base.NonGrammarTerminals.Add(Comment);
        }
    }
}

 

I analyzed this code line by line, I don't see any errors in it.

This is why it doesn't work:

I can declare class like that:

 

class test
{

}

 

And it works. But when I want to add some modifiers:

 

placeable class test
{

}

 

It gives me errors :(

Almost everything is not working lol.

It's my first grammar, so, you know.

Mar 18, 2012 at 2:10 PM

Hi, two comments if they help.

1. I think you would do well to lose all of the RegexBasedTerminals.  Use things like IdentifierTerminal, NumberLiteral and StringLiteral.  Dont forget you can specify additional options to make these operate the way you need them to, such as using additional characters. I have not had to use a RegexTerminal yet and I have 6 or so grammars with all their quirks running now.  For example I would personally prefer to use something like:

NonTerminal Modifier = new NonTerminal("Modifier");

Modifier.Rule = ToTerm("public") | "private" | "placeable";

2. I think you might have a prioritisation issue.  I seem to remember tackling something similar recently where I had a MakeStar list followed by additional stuff that I wasnt bothered about and simply wanted to lose into a FreeTextLiteral.  The FreeTextLiteral consumed my list and the MakeStar rule was always empty.  I think "class" might be doing the same here, except "class" is not the same as "placeable" and so it fails.  Looking at the pattern I used to solve this problem, you might make "class" a lower priority. So I imagine that would be something like this:

Terminal ClassTerm = ToTerm("class");

ClassTerm.Priority = Terminal.LowestPriority;

ClassDeclaration.Rule = ModifierList + ClassTerm + Identifier + CodeBlock;