The IronMeta Grammar

The following is the grammar used for parsing IronMeta files themselves, presented purely for interest.

//////////////////////////////////////////////////////////////////////
// Copyright (c) 2009, The IronMeta Project
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without 
// modification, are permitted provided that the following conditions 
// are met:
// 
//     * Redistributions of source code must retain the above 
//       copyright notice, this list of conditions and the following 
//       disclaimer.
//     * Redistributions in binary form must reproduce the above 
//       copyright notice, this list of conditions and the following 
//       disclaimer in the documentation and/or other materials 
//       provided with the distribution.
//     * Neither the name of the IronMeta Project nor the names of its 
//       contributors may be used to endorse or promote products 
//       derived from this software without specific prior written 
//       permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND  ANY EXPRESS OR  IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE  IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS 
// FOR  A  PARTICULAR  PURPOSE  ARE DISCLAIMED. IN  NO EVENT SHALL THE 
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
// BUT NOT  LIMITED TO, PROCUREMENT  OF SUBSTITUTE  GOODS  OR SERVICES; 
// LOSS OF USE, DATA, OR  PROFITS; OR  BUSINESS  INTERRUPTION) HOWEVER 
// CAUSED AND ON ANY THEORY OF  LIABILITY, WHETHER IN CONTRACT, STRICT 
// LIABILITY, OR  TORT (INCLUDING NEGLIGENCE  OR OTHERWISE) ARISING IN 
// ANY WAY OUT  OF THE  USE OF THIS SOFTWARE, EVEN  IF ADVISED  OF THE 
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////

ironMeta IronMeta<char, IronMeta.SyntaxNode> : IronMeta.CharacterMatcher<IronMeta.SyntaxNode>
{

    IronMetaFile = Spacing FilePreamble?:pre IronMetaParser*:parsers EOF
                -> { return new IronMetaFileNode(_IM_StartIndex, pre, parsers); };

    FilePreamble = ( UsingStatement )+;
    
    UsingStatement = KW("using") QualifiedIdentifier:id (KW(",") | KW(";"))
                -> { return new UsingStatementNode(_IM_StartIndex, _IM_GetText(id)); };
    
    IronMetaParser = KW("ironMeta") ParserDeclaration:decl ParserBody:body
                -> { return new ParserNode(_IM_StartIndex, decl, body); };
    
    ParserDeclaration = GenericIdentifier:name BaseClassDeclaration?:bc
                -> { return new ParserDeclarationNode(_IM_StartIndex, name, bc); };
    
    BaseClassDeclaration = KW(":") GenericIdentifier:id
                -> { return id; };
    
    
    
    ParserBody = KW("{") Rule*:rules KW("}")
                -> { return new ParserBodyNode(_IM_StartIndex, rules); };
    
    Rule = KW("override")?:ovr Identifier:name Disjunction?:parms (KW("::=") | KW("=")) Disjunction:body (KW(",") | KW(";"))
                -> {
                        bool isOverride = ovr.Results.Any();
                        SyntaxNode pNode = parms.Results.Any() ? (SyntaxNode)parms : null;
                        return new RuleNode(_IM_StartIndex, isOverride, name, pNode, body);
                    };
    
    Disjunction = Disjunction:a KW("|") ActionExpression:b
                    -> { return new DisjunctionExpNode(_IM_StartIndex, a, b); } 
                | ActionExpression;
    
    ActionExpression = FailExpression;
        
    ActionExpression = SequenceExpression:exp ((KW("->") | KW("=>")) &'{' CSharpCode:action)
                    -> { return new ActionExpNode(_IM_StartIndex, exp, action); }
                | SequenceExpression;

    FailExpression = KW("!") (&'\"' CSharpCode:str)?
                    -> { return new FailExpNode(_IM_StartIndex, str); };

    SequenceExpression = SequenceExpression:a ConditionExpression:b 
                    -> { return new SequenceExpNode(_IM_StartIndex, a, b); }
                | ConditionExpression;
    
    ConditionExpression = BoundTerm:exp ('?' &'(') CSharpCode:cond
                    -> { return new ConditionExpNode(_IM_StartIndex, exp, cond); }
                | BoundTerm;
    
    BoundTerm = PrefixedTerm:exp KW(":") Identifier:id
                    -> { return new BoundExpNode(_IM_StartIndex, exp, id); }
                | KW(":") Identifier:id
                    -> { return new BoundExpNode(_IM_StartIndex, new AnyExpNode(_IM_StartIndex), id); }
                | PrefixedTerm;
    
    
    PrefixedTerm = AndTerm | NotTerm | PostfixedTerm;
    
    AndTerm = KW("&") PrefixedTerm:exp
            -> { return new PrefixedExpNode(_IM_StartIndex, exp, "LOOK"); };
    
    NotTerm = KW("~") PrefixedTerm:exp
            -> { return new PrefixedExpNode(_IM_StartIndex, exp, "NOT"); };
    
    
    PostfixedTerm = StarTerm | PlusTerm | QuestionTerm | Term;
    
    StarTerm = PostfixedTerm:exp KW("*")
            -> { return new PostfixedExpNode(_IM_StartIndex, exp, "STAR"); };
    
    PlusTerm = PostfixedTerm:exp KW("+")
            -> { return new PostfixedExpNode(_IM_StartIndex, exp, "PLUS"); };
    
    QuestionTerm = PostfixedTerm:exp ('?' ~'(' Spacing)
            -> { return new PostfixedExpNode(_IM_StartIndex, exp, "QUES"); }; 
    
    
    Term = ParenTerm | AnyTerm | RuleCall | CallOrVar | Literal;
    
    ParenTerm = KW("(") Disjunction:exp KW(")")
            -> { return exp; };
    
    AnyTerm = KW(".")
            -> { return new AnyExpNode(_IM_StartIndex); };
    
    RuleCall = QualifiedIdentifier:name KW("(") ParameterList?:p KW(")")
            -> { return new RuleCallExpNode(_IM_StartIndex, _IM_GetText(name), p); };
    
    ParameterList = Parameter (KW(",") Parameter)* 
            -> { return _IM_Result.Results.Where(child => child is CallOrVarExpNode || child is LiteralExpNode); };
            
    Parameter = CallOrVar | Literal;
            
    CallOrVar = QualifiedIdentifier
            -> { return new CallOrVarExpNode(_IM_StartIndex, _IM_Result); };

    Literal = &('\"' | '\'' | '{') CSharpCode
            -> { return new LiteralExpNode(_IM_StartIndex, _IM_Result); };

    
    CSharpCode = CSharpCodeItem:code Spacing
            -> { return new CSharpNode(_IM_StartIndex, _IM_GetText(code)); };

    CSharpCodeItem = '{' ((~'}') (CSharpCodeItem | Comment | EOL | .))* '}'
                   | '(' ((~')') (CSharpCodeItem | Comment | EOL | .))* ')'
                   | '\"' ( ('\x5c' '\x5c') | ('\x5c' '\"') | ((~'\"') (EOL | .)) )* '\"'
                   | '\'' ( ('\x5c' '\x5c') | ('\x5c' '\'') | ((~'\'') (EOL | .)) )* '\'';


    GenericIdentifier = QualifiedIdentifier:id (KW("<") (GenericIdentifier (KW(",") GenericIdentifier)*):p KW(">"))?
            -> {
                    List<string> pl = p.Results
                                        .Where(node => node is IdentifierNode)
                                        .Select(node => node.Text).ToList();
                    IdentifierNode idn = (IdentifierNode)id;
                    return new IdentifierNode(_IM_StartIndex, idn.Name, idn.Qualifiers, pl);
                };

    QualifiedIdentifier = (Identifier KW("."))*:quals Identifier:name
            -> {
                    var ql = quals.Results.Where(node => node is IdentifierNode).Select(node => node.Text).ToList();
                    return new IdentifierNode(_IM_StartIndex, ((IdentifierNode)name).Name, ql, null);
                };
    
    Identifier = (. ?(_IM_Result == '_' || System.Char.IsLetter(_IM_Result))) 
                 (. ?(_IM_Result == '_' || System.Char.IsLetterOrDigit(_IM_Result)))*
                 Spacing
            -> { return new IdentifierNode(_IM_StartIndex, _IM_GetText(_IM_Result).Trim()); };


    Spacing = (Comment | Whitespace)*:nodes
            -> { return new SpacingNode(_IM_StartIndex, nodes); };
    
    Comment = (  '/' '/' (~('\r'|'\n') .)* (EOL|EOF)
               | '/' '*' (~('*' '/') (EOL | .))* '*' '/' )
            -> { return new CommentNode(_IM_StartIndex, _IM_GetText(_IM_Result)); };


    KW .*:kw = kw:str Spacing
            -> { return new KeywordNode(_IM_StartIndex, _IM_GetText(str)); };
    
    
    // EOL needs to be first, as otherwise it won't add the position to the list    
    override Whitespace = EOL | . ?(System.Char.IsWhiteSpace(_IM_Result)) 
                                -> { return new TokenNode(_IM_StartIndex, TokenNode.TokenType.WHITESPACE); };


    override EOL = ('\r' '\n' | '\r' ~'\n' | '\n') 
            -> {
                    _IM_LineBeginPositions.Add(_IM_NextIndex);
                    return new TokenNode(_IM_StartIndex, TokenNode.TokenType.EOL); 
                };
    
    override EOF = ~. 
            -> { _IM_LineBeginPositions.Add(_IM_StartIndex); return new TokenNode(_IM_StartIndex, TokenNode.TokenType.EOF); };
    
}

Copyright (C) 2009 The IronMeta Project Get IronMeta at SourceForge.net. Fast, secure and Free Open Source software downloads Support This Project