1750 lines
54 KiB
Plaintext
1750 lines
54 KiB
Plaintext
/*
|
|
* [The "BSD license"]
|
|
* Copyright (c) 2011 Terence Parr
|
|
* All rights reserved.
|
|
*
|
|
* Conversion to C#:
|
|
* Copyright (c) 2011 Sam Harwell, Pixel Mine, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. 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.
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
|
*/
|
|
|
|
csharpVisibilityMap ::= [
|
|
"private":"private",
|
|
"protected":"protected",
|
|
"public":"public",
|
|
"fragment":"private",
|
|
default:"private"
|
|
]
|
|
|
|
/** The overall file structure of a recognizer; stores methods for rules
|
|
* and cyclic DFAs plus support code.
|
|
*/
|
|
outputFile( LEXER,PARSER,TREE_PARSER, actionScope, actions,
|
|
docComment, recognizer,
|
|
name, tokens, tokenNames, rules, cyclicDFAs,
|
|
bitsets, buildTemplate, buildAST, rewriteMode, profile,
|
|
backtracking, synpreds, memoize, numRules,
|
|
fileName, ANTLRVersion, generatedTimestamp, trace,
|
|
scopes, superClass, literals) ::=
|
|
<<
|
|
//------------------------------------------------------------------------------
|
|
// \<auto-generated>
|
|
// This code was generated by a tool.
|
|
// ANTLR Version: <ANTLRVersion>
|
|
//
|
|
// Changes to this file may cause incorrect behavior and will be lost if
|
|
// the code is regenerated.
|
|
// \</auto-generated>
|
|
//------------------------------------------------------------------------------
|
|
|
|
// $ANTLR <ANTLRVersion> <fileName> <generatedTimestamp>
|
|
|
|
// The variable 'variable' is assigned but its value is never used.
|
|
#pragma warning disable 219
|
|
// Unreachable code detected.
|
|
#pragma warning disable 162
|
|
// Missing XML comment for publicly visible type or member 'Type_or_Member'
|
|
#pragma warning disable 1591
|
|
// CLS compliance checking will not be performed on 'type' because it is not visible from outside this assembly.
|
|
#pragma warning disable 3019
|
|
|
|
<actions.(actionScope).header>
|
|
|
|
<@imports>
|
|
using System.Collections.Generic;
|
|
using Antlr.Runtime;
|
|
using Antlr.Runtime.Misc;
|
|
<if(TREE_PARSER)>
|
|
using Antlr.Runtime.Tree;
|
|
using RewriteRuleITokenStream = Antlr.Runtime.Tree.RewriteRuleTokenStream;
|
|
<endif>
|
|
<@end>
|
|
<if(actions.(actionScope).namespace)>
|
|
namespace <actions.(actionScope).namespace>
|
|
{
|
|
<endif>
|
|
<docComment>
|
|
<recognizer>
|
|
<if(actions.(actionScope).namespace)>
|
|
|
|
} // namespace <actions.(actionScope).namespace>
|
|
<endif>
|
|
>>
|
|
|
|
lexerInputStreamType() ::= <<
|
|
<actions.(actionScope).inputStreamType; null="ICharStream">
|
|
>>
|
|
|
|
lexer(grammar, name, tokens, scopes, rules, numRules, filterMode, labelType="CommonToken",
|
|
superClass={<if(actions.(actionScope).superClass)><actions.(actionScope).superClass><else>Antlr.Runtime.Lexer<endif>},
|
|
rewriteElementType={}, ASTLabelType={}) ::= <<
|
|
[System.CodeDom.Compiler.GeneratedCode("ANTLR", "<ANTLRVersion>")]
|
|
[System.CLSCompliant(false)]
|
|
<parserModifier(grammar=grammar, actions=actions)> partial class <grammar.recognizerName> : <@superClassName><superClass><@end>
|
|
{
|
|
<tokens:{it|public const int <it.name; format="id">=<it.type>;}; separator="\n">
|
|
<scopes:{it|<if(it.isDynamicGlobalScope)><globalAttributeScope(scope=it)><endif>}>
|
|
<actions.lexer.members>
|
|
|
|
// delegates
|
|
<grammar.delegates:
|
|
{g|private <g.recognizerName> <g:delegateName()>;}; separator="\n">
|
|
// delegators
|
|
<grammar.delegators:
|
|
{g|private <g.recognizerName> <g:delegateName()>;}; separator="\n">
|
|
<last(grammar.delegators):{g|private <g.recognizerName> gParent;}>
|
|
|
|
<actions.(actionScope).ctorModifier; null="public"> <grammar.recognizerName>()<! needed by subclasses !>
|
|
{
|
|
OnCreated();
|
|
}
|
|
|
|
<actions.(actionScope).ctorModifier; null="public"> <grammar.recognizerName>(<lexerInputStreamType()> input<grammar.delegators:{g|, <g.recognizerName> <g:delegateName()>}> )
|
|
: this(input, new RecognizerSharedState()<grammar.delegators:{g|, <g:delegateName()>}>)
|
|
{
|
|
}
|
|
|
|
<actions.(actionScope).ctorModifier; null="public"> <grammar.recognizerName>(<lexerInputStreamType()> input, RecognizerSharedState state<grammar.delegators:{g|, <g.recognizerName> <g:delegateName()>}>)
|
|
: base(input, state)
|
|
{
|
|
<if(memoize)>
|
|
<if(grammar.grammarIsRoot)>
|
|
state.ruleMemo = new System.Collections.Generic.Dictionary\<int, int>[<numRules>+1];<\n><! index from 1..n !>
|
|
<endif>
|
|
<endif>
|
|
<grammar.directDelegates:
|
|
{g|<g:delegateName()> = new <g.recognizerName>(input, this.state<trunc(g.delegators):{p|, <p:delegateName()>}>, this);}; separator="\n">
|
|
<grammar.delegators:
|
|
{g|this.<g:delegateName()> = <g:delegateName()>;}; separator="\n">
|
|
<last(grammar.delegators):{g|gParent = <g:delegateName()>;}>
|
|
|
|
OnCreated();
|
|
}
|
|
public override string GrammarFileName { get { return "<fileName>"; } }
|
|
|
|
<if(grammar.hasDelegates)>
|
|
public override <lexerInputStreamType()> CharStream
|
|
{
|
|
get
|
|
{
|
|
return base.CharStream;
|
|
}
|
|
set
|
|
{
|
|
base.CharStream = value;
|
|
<grammar.directDelegates:
|
|
{g|<g:delegateName()> = new <g.recognizerName>(input, state<trunc(g.delegators):{p|, <p:delegateName()>}>, this);}; separator="\n">
|
|
<grammar.delegators:
|
|
{g|this.<g:delegateName()> = <g:delegateName()>;}; separator="\n">
|
|
<last(grammar.delegators):{g|gParent = <g:delegateName()>;}>
|
|
}
|
|
}
|
|
|
|
<if(grammar.delegates)>
|
|
public override void SetState(RecognizerSharedState state)
|
|
{
|
|
base.SetState(state);
|
|
<grammar.delegates:{g|<g:delegateName()>.SetState(state);}; separator="\n">
|
|
}
|
|
<endif>
|
|
|
|
<endif>
|
|
<if(filterMode)>
|
|
<filteringNextToken()>
|
|
<endif>
|
|
|
|
|
|
partial void OnCreated();
|
|
partial void EnterRule(string ruleName, int ruleIndex);
|
|
partial void LeaveRule(string ruleName, int ruleIndex);
|
|
|
|
<rules; separator="\n">
|
|
|
|
<insertLexerSynpreds(synpreds)>
|
|
|
|
#region DFA
|
|
<cyclicDFAs:{dfa | DFA<dfa.decisionNumber> dfa<dfa.decisionNumber>;}; separator="\n">
|
|
|
|
protected override void InitDFAs()
|
|
{
|
|
base.InitDFAs();
|
|
<cyclicDFAs:{dfa | dfa<dfa.decisionNumber> = new DFA<dfa.decisionNumber>(this<if(dfa.specialStateSTs)>, SpecialStateTransition<dfa.decisionNumber><endif>);}; separator="\n">
|
|
}
|
|
|
|
<cyclicDFAs:cyclicDFA()> <! dump tables for all DFA !>
|
|
#endregion
|
|
|
|
}
|
|
>>
|
|
|
|
/** A override of Lexer.nextToken() that backtracks over mTokens() looking
|
|
* for matches. No error can be generated upon error; just rewind, consume
|
|
* a token and then try again. backtracking needs to be set as well.
|
|
* Make rule memoization happen only at levels above 1 as we start mTokens
|
|
* at backtracking==1.
|
|
*/
|
|
filteringNextToken() ::= <<
|
|
public override IToken NextToken()
|
|
{
|
|
while (true)
|
|
{
|
|
if (input.LA(1) == CharStreamConstants.EndOfFile)
|
|
{
|
|
IToken eof = new CommonToken((ICharStream)input, CharStreamConstants.EndOfFile, TokenChannels.Default, input.Index, input.Index);
|
|
eof.Line = Line;
|
|
eof.CharPositionInLine = CharPositionInLine;
|
|
return eof;
|
|
}
|
|
state.token = null;
|
|
state.channel = TokenChannels.Default;
|
|
state.tokenStartCharIndex = input.Index;
|
|
state.tokenStartCharPositionInLine = input.CharPositionInLine;
|
|
state.tokenStartLine = input.Line;
|
|
state.text = null;
|
|
try
|
|
{
|
|
int m = input.Mark();
|
|
state.backtracking=1;<! means we won't throw slow exception !>
|
|
state.failed=false;
|
|
mTokens();
|
|
state.backtracking=0;
|
|
<! mTokens backtracks with synpred at backtracking==2
|
|
and we set the synpredgate to allow actions at level 1. !>
|
|
if (state.failed)
|
|
{
|
|
input.Rewind(m);
|
|
input.Consume();<! advance one char and try again !>
|
|
}
|
|
else
|
|
{
|
|
Emit();
|
|
return state.token;
|
|
}
|
|
}
|
|
catch (RecognitionException re)
|
|
{
|
|
// shouldn't happen in backtracking mode, but...
|
|
ReportError(re);
|
|
Recover(re);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Memoize(IIntStream input, int ruleIndex, int ruleStartIndex)
|
|
{
|
|
if (state.backtracking > 1)
|
|
base.Memoize(input, ruleIndex, ruleStartIndex);
|
|
}
|
|
|
|
public override bool AlreadyParsedRule(IIntStream input, int ruleIndex)
|
|
{
|
|
if (state.backtracking > 1)
|
|
return base.AlreadyParsedRule(input, ruleIndex);
|
|
|
|
return false;
|
|
}
|
|
>>
|
|
|
|
actionGate() ::= "state.backtracking == 0"
|
|
|
|
filteringActionGate() ::= "state.backtracking == 1"
|
|
|
|
/** How to generate a parser */
|
|
genericParser(grammar, name, scopes, tokens, tokenNames, rules, numRules,
|
|
bitsets, inputStreamType, superClass,
|
|
labelType, members, rewriteElementType,
|
|
filterMode, ASTLabelType="object") ::= <<
|
|
[System.CodeDom.Compiler.GeneratedCode("ANTLR", "<ANTLRVersion>")]
|
|
[System.CLSCompliant(false)]
|
|
<parserModifier(grammar=grammar, actions=actions)> partial class <grammar.recognizerName> : <@superClassName><superClass><@end>
|
|
{
|
|
<if(grammar.grammarIsRoot)>
|
|
internal static readonly string[] tokenNames = new string[] {
|
|
"\<invalid>", "\<EOR>", "\<DOWN>", "\<UP>", <tokenNames; separator=", ">
|
|
};
|
|
<endif>
|
|
<tokens:{it|public const int <it.name; format="id">=<it.type>;}; separator="\n">
|
|
|
|
<if(grammar.delegates)>
|
|
// delegates
|
|
<grammar.delegates:
|
|
{g|private <g.recognizerName> <g:delegateName()>;}; separator="\n">
|
|
<endif>
|
|
<if(grammar.delegators)>
|
|
// delegators
|
|
<grammar.delegators:
|
|
{g|private <g.recognizerName> <g:delegateName()>;}; separator="\n">
|
|
<last(grammar.delegators):{g|private <g.recognizerName> gParent;}>
|
|
<endif>
|
|
|
|
<if(grammar.delegates)>
|
|
public override void SetState(RecognizerSharedState state)
|
|
{
|
|
base.SetState(state);
|
|
<grammar.delegates:{g|<g:delegateName()>.SetState(state);}; separator="\n">
|
|
}
|
|
|
|
<if(TREE_PARSER)>
|
|
public override void SetTreeNodeStream(ITreeNodeStream input)
|
|
{
|
|
base.SetTreeNodeStream(input);
|
|
<grammar.delegates:{g|<g:delegateName()>.SetTreeNodeStream(input);}; separator="\n">
|
|
}
|
|
<endif>
|
|
<endif>
|
|
|
|
<scopes:{it|<if(it.isDynamicGlobalScope)><globalAttributeScope(scope=it)><endif>}>
|
|
<@members()>
|
|
|
|
public override string[] TokenNames { get { return <grammar.composite.rootGrammar.recognizerName>.tokenNames; } }
|
|
public override string GrammarFileName { get { return "<fileName>"; } }
|
|
|
|
<members>
|
|
|
|
partial void OnCreated();
|
|
partial void EnterRule(string ruleName, int ruleIndex);
|
|
partial void LeaveRule(string ruleName, int ruleIndex);
|
|
|
|
#region Rules
|
|
<rules; separator="\n">
|
|
#endregion Rules
|
|
|
|
<if(grammar.delegatedRules)>
|
|
<! generate rule/method definitions for imported rules so they
|
|
appear to be defined in this recognizer. !>
|
|
#region Delegated rules
|
|
<grammar.delegatedRules:{ruleDescriptor|
|
|
<ruleModifier(grammar=grammar,ruleDescriptor=ruleDescriptor)> <returnType(ruleDescriptor)> <ruleDescriptor.name; format="id">(<ruleDescriptor.parameterScope:parameterScope()>) <!throws RecognitionException !>{ <if(ruleDescriptor.hasReturnValue)>return <endif><ruleDescriptor.grammar:delegateName()>.<ruleDescriptor.name; format="id">(<ruleDescriptor.parameterScope.attributes:{a|<a.name; format="id">}; separator=", ">); \}}; separator="\n">
|
|
#endregion Delegated rules
|
|
<endif>
|
|
|
|
<insertSynpreds(synpreds)>
|
|
|
|
<if(cyclicDFAs)>
|
|
#region DFA
|
|
<cyclicDFAs:{dfa | private DFA<dfa.decisionNumber> dfa<dfa.decisionNumber>;}; separator="\n">
|
|
|
|
protected override void InitDFAs()
|
|
{
|
|
base.InitDFAs();
|
|
<cyclicDFAs:{dfa | dfa<dfa.decisionNumber> = new DFA<dfa.decisionNumber>( this<if(dfa.specialStateSTs)>, SpecialStateTransition<dfa.decisionNumber><endif> );}; separator="\n">
|
|
}
|
|
|
|
<cyclicDFAs:cyclicDFA()><! dump tables for all DFA !>
|
|
#endregion DFA
|
|
<endif>
|
|
|
|
<if(bitsets)>
|
|
#region Follow sets
|
|
private static class Follow
|
|
{
|
|
<bitsets:{it|<bitset(name={_<it.name>_in_<it.inName><it.tokenIndex>}, words64=it.bits)>}; separator="\n">
|
|
}
|
|
#endregion Follow sets
|
|
<endif>
|
|
}
|
|
>>
|
|
|
|
@genericParser.members() ::= <<
|
|
<! WARNING. bug in ST: this is cut-n-paste into Dbg.stg !>
|
|
<actions.(actionScope).ctorModifier; null="public"> <grammar.recognizerName>(<inputStreamType> input<grammar.delegators:{g|, <g.recognizerName> <g:delegateName()>}>)
|
|
: this(input, new RecognizerSharedState()<grammar.delegators:{g|, <g:delegateName()>}>)
|
|
{
|
|
}
|
|
<actions.(actionScope).ctorModifier; null="public"> <grammar.recognizerName>(<inputStreamType> input, RecognizerSharedState state<grammar.delegators:{g|, <g.recognizerName> <g:delegateName()>}>)
|
|
: base(input, state)
|
|
{
|
|
<if(grammar.directDelegates)>
|
|
<grammar.directDelegates:
|
|
{g|<g:delegateName()> = new <g.recognizerName>(input, state<trunc(g.delegators):{p|, <p:delegateName()>}>, this);}; separator="\n">
|
|
<endif>
|
|
<if(grammar.indirectDelegates)>
|
|
<grammar.indirectDelegates:{g | <g:delegateName()> = <g.delegator:delegateName()>.<g:delegateName()>;}; separator="\n">
|
|
<endif>
|
|
<if(grammar.delegators)>
|
|
<last(grammar.delegators):{g|gParent = <g:delegateName()>;}>
|
|
<endif>
|
|
<parserCtorBody()>
|
|
OnCreated();
|
|
}
|
|
>>
|
|
|
|
// imported grammars are 'public' (can't be internal because their return scope classes must be accessible)
|
|
parserModifier(grammar, actions) ::= <<
|
|
<if(grammar.grammarIsRoot)><actions.(actionScope).modifier; null="public"><else>public<endif>
|
|
>>
|
|
|
|
parserCtorBody() ::= <<
|
|
<if(memoize)>
|
|
<if(grammar.grammarIsRoot)>
|
|
this.state.ruleMemo = new System.Collections.Generic.Dictionary\<int, int>[<length(grammar.allImportedRules)>+1];<\n><! index from 1..n !>
|
|
<endif>
|
|
<endif>
|
|
<grammar.delegators:
|
|
{g|this.<g:delegateName()> = <g:delegateName()>;}; separator="\n">
|
|
>>
|
|
|
|
parser(grammar, name, scopes, tokens, tokenNames, rules, numRules, bitsets,
|
|
ASTLabelType="object", superClass={<if(actions.(actionScope).superClass)><actions.(actionScope).superClass><else>Antlr.Runtime.Parser<endif>}, labelType="IToken",
|
|
members={<actions.parser.members>}) ::= <<
|
|
<genericParser(inputStreamType="ITokenStream", rewriteElementType="IToken", filterMode=false, ...)>
|
|
>>
|
|
|
|
/** How to generate a tree parser; same as parser except the input
|
|
* stream is a different type.
|
|
*/
|
|
treeParser(grammar, name, scopes, tokens, tokenNames, globalAction, rules,
|
|
numRules, bitsets, filterMode, labelType={<ASTLabelType>}, ASTLabelType="object",
|
|
superClass={<if(actions.(actionScope).superClass)><actions.(actionScope).superClass><else>Antlr.Runtime.Tree.<if(filterMode)><if(buildAST)>TreeRewriter<else>TreeFilter<endif><else>TreeParser<endif><endif>},
|
|
members={<actions.treeparser.members>}) ::= <<
|
|
<genericParser(inputStreamType="ITreeNodeStream", rewriteElementType="Node", ...)>
|
|
>>
|
|
|
|
/** A simpler version of a rule template that is specific to the imaginary
|
|
* rules created for syntactic predicates. As they never have return values
|
|
* nor parameters etc..., just give simplest possible method. Don't do
|
|
* any of the normal memoization stuff in here either; it's a waste.
|
|
* As predicates cannot be inlined into the invoking rule, they need to
|
|
* be in a rule by themselves.
|
|
*/
|
|
synpredRule(ruleName, ruleDescriptor, block, description, nakedBlock) ::=
|
|
<<
|
|
|
|
partial void EnterRule_<ruleName>_fragment();
|
|
partial void LeaveRule_<ruleName>_fragment();
|
|
|
|
// $ANTLR start <ruleName>
|
|
public <!final !>void <ruleName>_fragment(<ruleDescriptor.parameterScope:parameterScope()>)
|
|
{
|
|
<ruleLabelDefs(...)>
|
|
EnterRule_<ruleName>_fragment();
|
|
EnterRule("<ruleName>_fragment", <ruleDescriptor.index>);
|
|
TraceIn("<ruleName>_fragment", <ruleDescriptor.index>);
|
|
try
|
|
{
|
|
<block>
|
|
}
|
|
finally
|
|
{
|
|
TraceOut("<ruleName>_fragment", <ruleDescriptor.index>);
|
|
LeaveRule("<ruleName>_fragment", <ruleDescriptor.index>);
|
|
LeaveRule_<ruleName>_fragment();
|
|
}
|
|
}
|
|
// $ANTLR end <ruleName>
|
|
>>
|
|
|
|
insertLexerSynpreds(synpreds) ::= <<
|
|
<insertSynpreds(synpreds)>
|
|
>>
|
|
|
|
insertSynpreds(synpreds) ::= <<
|
|
<if(synpreds)>
|
|
#region Synpreds
|
|
private bool EvaluatePredicate(System.Action fragment)
|
|
{
|
|
bool success = false;
|
|
state.backtracking++;
|
|
<@start()>
|
|
try { DebugBeginBacktrack(state.backtracking);
|
|
int start = input.Mark();
|
|
try
|
|
{
|
|
fragment();
|
|
}
|
|
catch ( RecognitionException re )
|
|
{
|
|
System.Console.Error.WriteLine("impossible: "+re);
|
|
}
|
|
success = !state.failed;
|
|
input.Rewind(start);
|
|
} finally { DebugEndBacktrack(state.backtracking, success); }
|
|
<@stop()>
|
|
state.backtracking--;
|
|
state.failed=false;
|
|
return success;
|
|
}
|
|
#endregion Synpreds
|
|
<endif>
|
|
>>
|
|
|
|
ruleMemoization(name) ::= <<
|
|
<if(memoize)>
|
|
if (state.backtracking > 0 && AlreadyParsedRule(input, <ruleDescriptor.index>)) { <returnFromRule()> }
|
|
<endif>
|
|
>>
|
|
|
|
/** How to test for failure and return from rule */
|
|
checkRuleBacktrackFailure() ::= <<
|
|
<if(backtracking)>if (state.failed) <returnFromRule()><endif>
|
|
>>
|
|
|
|
/** This rule has failed, exit indicating failure during backtrack */
|
|
ruleBacktrackFailure() ::= <<
|
|
<if(backtracking)>if (state.backtracking>0) {state.failed=true; <returnFromRule()>}<endif>
|
|
>>
|
|
|
|
ruleWrapperMap ::= [
|
|
"bottomup":{<ruleWrapperBottomup()>},
|
|
"topdown":{<ruleWrapperTopdown()>},
|
|
default:""
|
|
]
|
|
|
|
ruleWrapperBottomup() ::= <<
|
|
<if(TREE_PARSER && filterMode)>
|
|
protected override <if(buildAST)>IAstRuleReturnScope<else>void<endif> Bottomup() { <if(buildAST)>return <endif>bottomup(); }
|
|
<endif>
|
|
>>
|
|
|
|
ruleWrapperTopdown() ::= <<
|
|
<if(TREE_PARSER && filterMode)>
|
|
protected override <if(buildAST)>IAstRuleReturnScope<else>void<endif> Topdown() { <if(buildAST)>return <endif>topdown(); }
|
|
<endif>
|
|
>>
|
|
|
|
/** How to generate code for a rule. This includes any return type
|
|
* data aggregates required for multiple return values.
|
|
*/
|
|
rule(ruleName,ruleDescriptor,block,emptyRule,description,exceptions,finally,memoize) ::= <<
|
|
<ruleAttributeScope(scope=ruleDescriptor.ruleScope)>
|
|
<returnScope(ruleDescriptor.returnScope)>
|
|
partial void EnterRule_<ruleName>();
|
|
partial void LeaveRule_<ruleName>();
|
|
<ruleWrapperMap.(ruleName)>
|
|
// $ANTLR start "<ruleName>"
|
|
// <fileName>:<description>
|
|
[GrammarRule("<ruleName>")]
|
|
<ruleModifier(grammar=grammar,ruleDescriptor=ruleDescriptor)> <returnType(ruleDescriptor)> <ruleName; format="id">(<ruleDescriptor.parameterScope:parameterScope()>)
|
|
{
|
|
EnterRule_<ruleName>();
|
|
EnterRule("<ruleName>", <ruleDescriptor.index>);
|
|
TraceIn("<ruleName>", <ruleDescriptor.index>);
|
|
<ruleScopeSetUp()>
|
|
<ruleDeclarations()>
|
|
<ruleLabelDefs(...)>
|
|
<ruleDescriptor.actions.init>
|
|
try { DebugEnterRule(GrammarFileName, "<ruleName>");
|
|
DebugLocation(<ruleDescriptor.tree.line>, <ruleDescriptor.EORNode.charPositionInLine>);
|
|
<@preamble()>
|
|
try
|
|
{
|
|
<ruleMemoization(name=ruleName)>
|
|
<block>
|
|
<ruleCleanUp()>
|
|
<(ruleDescriptor.actions.after):execAction()>
|
|
}
|
|
<if(exceptions)>
|
|
<exceptions:{e|<catch(decl=e.decl,action=e.action)><\n>}>
|
|
<else>
|
|
<if(!emptyRule)>
|
|
<if(actions.(actionScope).rulecatch)>
|
|
<actions.(actionScope).rulecatch>
|
|
<else>
|
|
catch (RecognitionException re)
|
|
{
|
|
ReportError(re);
|
|
Recover(input,re);
|
|
<@setErrorReturnValue()>
|
|
}
|
|
<endif>
|
|
<endif>
|
|
<endif>
|
|
finally
|
|
{
|
|
TraceOut("<ruleName>", <ruleDescriptor.index>);
|
|
LeaveRule("<ruleName>", <ruleDescriptor.index>);
|
|
LeaveRule_<ruleName>();
|
|
<memoize()>
|
|
<ruleScopeCleanUp()>
|
|
<finally>
|
|
}
|
|
DebugLocation(<ruleDescriptor.EORNode.line>, <ruleDescriptor.EORNode.charPositionInLine>);
|
|
} finally { DebugExitRule(GrammarFileName, "<ruleName>"); }
|
|
<@postamble()>
|
|
<returnFromRule()><\n>
|
|
}
|
|
// $ANTLR end "<ruleName>"
|
|
>>
|
|
|
|
// imported grammars need to have internal rules
|
|
ruleModifier(grammar,ruleDescriptor) ::= <<
|
|
<if(grammar.grammarIsRoot)><csharpVisibilityMap.(ruleDescriptor.modifier); null="private"><else>internal<endif>
|
|
>>
|
|
|
|
// imported grammars need to have public return scopes
|
|
returnScopeModifier(grammar,ruleDescriptor) ::= <<
|
|
<if(grammar.grammarIsRoot)><csharpVisibilityMap.(ruleDescriptor.modifier); null="private"><else>public<endif>
|
|
>>
|
|
|
|
catch(decl,action) ::= <<
|
|
catch (<e.decl>)
|
|
{
|
|
<e.action>
|
|
}
|
|
>>
|
|
|
|
ruleDeclarations() ::= <<
|
|
<if(ruleDescriptor.hasMultipleReturnValues)>
|
|
<returnType(ruleDescriptor)> retval = new <returnType(ruleDescriptor)>(<if(ruleDescriptor.returnScope.attributes)>this<endif>);
|
|
retval.Start = (<labelType>)input.LT(1);
|
|
<else>
|
|
<ruleDescriptor.returnScope.attributes:{ a |
|
|
<a.type> <a.name; format="id"> = <if(a.initValue)><a.initValue><else><initValue(a.type)><endif>;
|
|
}>
|
|
<endif>
|
|
<if(memoize)>
|
|
int <ruleDescriptor.name>_StartIndex = input.Index;
|
|
<endif>
|
|
>>
|
|
|
|
ruleScopeSetUp() ::= <<
|
|
<ruleDescriptor.useScopes:{it|<it>_stack.Push(new <it>_scope(this));<it>_scopeInit(<it>_stack.Peek());}; separator="\n">
|
|
<ruleDescriptor.ruleScope:{it|<it.name>_stack.Push(new <it.name>_scope(this));<it.name>_scopeInit(<it.name>_stack.Peek());}; separator="\n">
|
|
>>
|
|
|
|
ruleScopeCleanUp() ::= <<
|
|
<ruleDescriptor.useScopes:{it|<it>_scopeAfter(<it>_stack.Peek());<it>_stack.Pop();}; separator="\n">
|
|
<ruleDescriptor.ruleScope:{it|<it.name>_scopeAfter(<it.name>_stack.Peek());<it.name>_stack.Pop();}; separator="\n">
|
|
>>
|
|
|
|
ruleLabelDefs(ruleDescriptor, labelType, ASTLabelType, rewriteElementType) ::= <<
|
|
<[ruleDescriptor.tokenLabels,ruleDescriptor.tokenListLabels,ruleDescriptor.wildcardTreeLabels,ruleDescriptor.wildcardTreeListLabels]
|
|
:{it|<labelType> <it.label.text> = default(<labelType>);}; separator="\n"
|
|
>
|
|
<ruleDescriptor.tokenListLabels
|
|
:{it|List\<<labelType>\> list_<it.label.text> = null;}; separator="\n"
|
|
>
|
|
<[ruleDescriptor.ruleListLabels,ruleDescriptor.wildcardTreeListLabels]
|
|
:{it|List\<<ASTLabelType>\> list_<it.label.text> = null;}; separator="\n"
|
|
>
|
|
<ruleDescriptor.ruleLabels:ruleLabelDef(); separator="\n">
|
|
<ruleDescriptor.ruleListLabels:ruleLabelDef(); separator="\n">
|
|
>>
|
|
|
|
lexerRuleLabelDefs() ::= <<
|
|
<[ruleDescriptor.tokenLabels,
|
|
ruleDescriptor.tokenListLabels,
|
|
ruleDescriptor.ruleLabels]
|
|
:{it|<labelType> <it.label.text> = default(<labelType>);}; separator="\n"
|
|
>
|
|
<[ruleDescriptor.charListLabels,
|
|
ruleDescriptor.charLabels]
|
|
:{it|int <it.label.text> = 0;}; separator="\n"
|
|
>
|
|
<[ruleDescriptor.tokenListLabels,
|
|
ruleDescriptor.ruleListLabels]
|
|
:{it|List\<<labelType>\> list_<it.label.text> = null;}; separator="\n"
|
|
>
|
|
<ruleDescriptor.charListLabels:{it|List\<int\> list_<it.label.text> = null;}; separator="\n"
|
|
>
|
|
>>
|
|
|
|
returnFromRule() ::= <%
|
|
return
|
|
<if(!ruleDescriptor.isSynPred)>
|
|
<if(ruleDescriptor.hasReturnValue)>
|
|
<if(ruleDescriptor.hasSingleReturnValue)>
|
|
<! This comment is a hack to make sure the following
|
|
single space appears in the output. !> <ruleDescriptor.singleValueReturnName>
|
|
<else>
|
|
<!!> retval
|
|
<endif>
|
|
<endif>
|
|
<endif>
|
|
;
|
|
%>
|
|
|
|
ruleCleanUp() ::= <<
|
|
<if(ruleDescriptor.hasMultipleReturnValues)>
|
|
<if(!TREE_PARSER)>
|
|
retval.Stop = (<labelType>)input.LT(-1);
|
|
<endif>
|
|
<endif>
|
|
>>
|
|
|
|
memoize() ::= <<
|
|
<if(memoize)>
|
|
<if(backtracking)>
|
|
if (state.backtracking > 0) { Memoize(input, <ruleDescriptor.index>, <ruleDescriptor.name>_StartIndex); }
|
|
<endif>
|
|
<endif>
|
|
>>
|
|
|
|
/** How to generate a rule in the lexer; naked blocks are used for
|
|
* fragment rules.
|
|
*/
|
|
lexerRule(ruleName,nakedBlock,ruleDescriptor,block,memoize) ::= <<
|
|
|
|
partial void EnterRule_<ruleName>();
|
|
partial void LeaveRule_<ruleName>();
|
|
|
|
// $ANTLR start "<ruleName>"
|
|
[GrammarRule("<ruleName>")]
|
|
<ruleModifier(grammar=grammar,ruleDescriptor=ruleDescriptor)> void m<ruleName>(<ruleDescriptor.parameterScope:parameterScope()>)
|
|
{
|
|
EnterRule_<ruleName>();
|
|
EnterRule("<ruleName>", <ruleDescriptor.index>);
|
|
TraceIn("<ruleName>", <ruleDescriptor.index>);
|
|
<ruleScopeSetUp()>
|
|
<ruleDeclarations()>
|
|
try
|
|
{
|
|
<if(nakedBlock)>
|
|
<ruleMemoization(name=ruleName)>
|
|
<lexerRuleLabelDefs()>
|
|
<ruleDescriptor.actions.init>
|
|
<block>
|
|
<else>
|
|
int _type = <ruleName>;
|
|
int _channel = DefaultTokenChannel;
|
|
<ruleMemoization(name=ruleName)>
|
|
<lexerRuleLabelDefs()>
|
|
<ruleDescriptor.actions.init>
|
|
<block>
|
|
<ruleCleanUp()>
|
|
state.type = _type;
|
|
state.channel = _channel;
|
|
<(ruleDescriptor.actions.after):execAction()>
|
|
<endif>
|
|
}
|
|
finally
|
|
{
|
|
TraceOut("<ruleName>", <ruleDescriptor.index>);
|
|
LeaveRule("<ruleName>", <ruleDescriptor.index>);
|
|
LeaveRule_<ruleName>();
|
|
<ruleScopeCleanUp()>
|
|
<memoize()>
|
|
}
|
|
}
|
|
// $ANTLR end "<ruleName>"
|
|
>>
|
|
|
|
/** How to generate code for the implicitly-defined lexer grammar rule
|
|
* that chooses between lexer rules.
|
|
*/
|
|
tokensRule(ruleName,nakedBlock,args,block,ruleDescriptor) ::= <<
|
|
|
|
public override void mTokens()
|
|
{
|
|
<block><\n>
|
|
}
|
|
>>
|
|
|
|
// S U B R U L E S
|
|
|
|
/** A (...) subrule with multiple alternatives */
|
|
block(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= <<
|
|
// <fileName>:<description>
|
|
int alt<decisionNumber>=<maxAlt>;
|
|
<decls>
|
|
<@predecision()>
|
|
try { DebugEnterSubRule(<decisionNumber>);
|
|
try { DebugEnterDecision(<decisionNumber>, false<!<decision.dfa.hasSynPred>!>);
|
|
<decision>
|
|
} finally { DebugExitDecision(<decisionNumber>); }
|
|
<@postdecision()>
|
|
<@prebranch()>
|
|
switch (alt<decisionNumber>)
|
|
{
|
|
<alts:{a|<altSwitchCase(i,a)>}>
|
|
}
|
|
} finally { DebugExitSubRule(<decisionNumber>); }
|
|
<@postbranch()>
|
|
>>
|
|
|
|
/** A rule block with multiple alternatives */
|
|
ruleBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= <<
|
|
// <fileName>:<description>
|
|
int alt<decisionNumber>=<maxAlt>;
|
|
<decls>
|
|
<@predecision()>
|
|
try { DebugEnterDecision(<decisionNumber>, false<!<decision.dfa.hasSynPred>!>);
|
|
<decision>
|
|
} finally { DebugExitDecision(<decisionNumber>); }
|
|
<@postdecision()>
|
|
switch (alt<decisionNumber>)
|
|
{
|
|
<alts:{a|<altSwitchCase(i,a)>}>
|
|
}
|
|
>>
|
|
|
|
ruleBlockSingleAlt(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,description) ::= <<
|
|
// <fileName>:<description>
|
|
<decls>
|
|
<@prealt()>
|
|
DebugEnterAlt(1);
|
|
<alts>
|
|
<@postalt()>
|
|
>>
|
|
|
|
/** A special case of a (...) subrule with a single alternative */
|
|
blockSingleAlt(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,description) ::= <<
|
|
// <fileName>:<description>
|
|
<decls>
|
|
<@prealt()>
|
|
DebugEnterAlt(1);
|
|
<alts>
|
|
<@postalt()>
|
|
>>
|
|
|
|
/** A (..)+ block with 1 or more alternatives */
|
|
positiveClosureBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= <<
|
|
// <fileName>:<description>
|
|
int cnt<decisionNumber>=0;
|
|
<decls>
|
|
<@preloop()>
|
|
try { DebugEnterSubRule(<decisionNumber>);
|
|
while (true)
|
|
{
|
|
int alt<decisionNumber>=<maxAlt>;
|
|
<@predecision()>
|
|
try { DebugEnterDecision(<decisionNumber>, false<!<decision.dfa.hasSynPred>!>);
|
|
<decision>
|
|
} finally { DebugExitDecision(<decisionNumber>); }
|
|
<@postdecision()>
|
|
switch (alt<decisionNumber>)
|
|
{
|
|
<alts:{a|<altSwitchCase(i,a)>}>
|
|
default:
|
|
if (cnt<decisionNumber> >= 1)
|
|
goto loop<decisionNumber>;
|
|
|
|
<ruleBacktrackFailure()>
|
|
EarlyExitException eee<decisionNumber> = new EarlyExitException( <decisionNumber>, input );
|
|
DebugRecognitionException(eee<decisionNumber>);
|
|
<@earlyExitException()>
|
|
throw eee<decisionNumber>;
|
|
}
|
|
cnt<decisionNumber>++;
|
|
}
|
|
loop<decisionNumber>:
|
|
;
|
|
|
|
} finally { DebugExitSubRule(<decisionNumber>); }
|
|
<@postloop()>
|
|
>>
|
|
|
|
positiveClosureBlockSingleAlt ::= positiveClosureBlock
|
|
|
|
/** A (..)* block with 1 or more alternatives */
|
|
closureBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= <<
|
|
// <fileName>:<description>
|
|
<decls>
|
|
<@preloop()>
|
|
try { DebugEnterSubRule(<decisionNumber>);
|
|
while (true)
|
|
{
|
|
int alt<decisionNumber>=<maxAlt>;
|
|
<@predecision()>
|
|
try { DebugEnterDecision(<decisionNumber>, false<!<decision.dfa.hasSynPred>!>);
|
|
<decision>
|
|
} finally { DebugExitDecision(<decisionNumber>); }
|
|
<@postdecision()>
|
|
switch ( alt<decisionNumber> )
|
|
{
|
|
<alts:{a|<altSwitchCase(i,a)>}>
|
|
default:
|
|
goto loop<decisionNumber>;
|
|
}
|
|
}
|
|
|
|
loop<decisionNumber>:
|
|
;
|
|
|
|
} finally { DebugExitSubRule(<decisionNumber>); }
|
|
<@postloop()>
|
|
>>
|
|
|
|
closureBlockSingleAlt ::= closureBlock
|
|
|
|
/** Optional blocks (x)? are translated to (x|) by before code generation
|
|
* so we can just use the normal block template
|
|
*/
|
|
optionalBlock ::= block
|
|
|
|
optionalBlockSingleAlt ::= block
|
|
|
|
/** A case in a switch that jumps to an alternative given the alternative
|
|
* number. A DFA predicts the alternative and then a simple switch
|
|
* does the jump to the code that actually matches that alternative.
|
|
*/
|
|
altSwitchCase(altNum,alt) ::= <<
|
|
case <altNum>:
|
|
<@prealt()>
|
|
DebugEnterAlt(<altNum>);
|
|
<alt>
|
|
break;<\n>
|
|
>>
|
|
|
|
/** An alternative is just a list of elements; at outermost level */
|
|
alt(elements,altNum,description,autoAST,outerAlt,treeLevel,rew) ::= <<
|
|
// <fileName>:<description>
|
|
{
|
|
<@declarations()>
|
|
<elements:element()>
|
|
<rew>
|
|
<@cleanup()>
|
|
}
|
|
>>
|
|
|
|
/** What to emit when there is no rewrite. For auto build
|
|
* mode, does nothing.
|
|
*/
|
|
noRewrite(rewriteBlockLevel, treeLevel) ::= ""
|
|
|
|
// E L E M E N T S
|
|
|
|
/** Dump the elements one per line */
|
|
element(it) ::= <%
|
|
<@prematch()>
|
|
DebugLocation(<it.line>, <it.pos>);<\n>
|
|
<it.el><\n>
|
|
%>
|
|
|
|
/** match a token optionally with a label in front */
|
|
tokenRef(token,label,elementIndex,terminalOptions) ::= <<
|
|
<if(label)><label>=(<labelType>)<endif>Match(input,<token>,Follow._<token>_in_<ruleName><elementIndex>); <checkRuleBacktrackFailure()>
|
|
>>
|
|
|
|
/** ids+=ID */
|
|
tokenRefAndListLabel(token,label,elementIndex,terminalOptions) ::= <<
|
|
<tokenRef(...)>
|
|
<listLabelElem(elem=label,elemType=labelType,...)>
|
|
>>
|
|
|
|
listLabel(label,elem) ::= <<
|
|
#error The listLabel template should not be used with this target.<\n>
|
|
>>
|
|
|
|
listLabelElem(label,elem,elemType) ::= <<
|
|
if (list_<label>==null) list_<label>=new List\<<elemType; null={<labelType>}>\>();
|
|
list_<label>.Add(<elem>);<\n>
|
|
>>
|
|
|
|
/** match a character */
|
|
charRef(char,label) ::= <<
|
|
<if(label)>
|
|
<label> = input.LA(1);<\n>
|
|
<endif>
|
|
Match(<char>); <checkRuleBacktrackFailure()>
|
|
>>
|
|
|
|
/** match a character range */
|
|
charRangeRef(a,b,label) ::= <<
|
|
<if(label)>
|
|
<label> = input.LA(1);<\n>
|
|
<endif>
|
|
MatchRange(<a>,<b>); <checkRuleBacktrackFailure()>
|
|
>>
|
|
|
|
/** For now, sets are interval tests and must be tested inline */
|
|
matchSet(s,label,terminalOptions,elementIndex,postmatchCode="") ::= <<
|
|
<if(label)>
|
|
<matchSetLabel()>
|
|
<endif>
|
|
if (<s>)
|
|
{
|
|
input.Consume();
|
|
<postmatchCode>
|
|
<if(!LEXER)>state.errorRecovery=false;<endif><if(backtracking)>state.failed=false;<endif>
|
|
}
|
|
else
|
|
{
|
|
<ruleBacktrackFailure()>
|
|
MismatchedSetException mse = new MismatchedSetException(null,input);
|
|
DebugRecognitionException(mse);
|
|
<@mismatchedSetException()>
|
|
<if(LEXER)>
|
|
Recover(mse);
|
|
throw mse;
|
|
<else>
|
|
throw mse;
|
|
<! use following code to make it recover inline; remove throw mse;
|
|
recoverFromMismatchedSet(input,mse,Follow._set_in_<ruleName><elementIndex>);
|
|
!>
|
|
<endif>
|
|
}<\n>
|
|
>>
|
|
|
|
matchSetUnchecked(s,label,elementIndex,postmatchCode=false) ::= <%
|
|
<if(label)>
|
|
<matchSetLabel()><\n>
|
|
<endif>
|
|
input.Consume();<\n>
|
|
<if(postmatchCode)>
|
|
<postmatchCode><\n>
|
|
<endif>
|
|
<if(!LEXER)>state.errorRecovery=false;<endif><if(backtracking)>state.failed=false;<endif>
|
|
%>
|
|
|
|
matchSetLabel() ::= <%
|
|
<if(LEXER)>
|
|
<label>= input.LA(1);
|
|
<else>
|
|
<label>=(<labelType>)input.LT(1);
|
|
<endif>
|
|
%>
|
|
|
|
matchRuleBlockSet ::= matchSet
|
|
|
|
matchSetAndListLabel(s,label,elementIndex,postmatchCode) ::= <<
|
|
<matchSet(...)>
|
|
<listLabelElem(elem=label,elemType=labelType,...)>
|
|
>>
|
|
|
|
/** Match a string literal */
|
|
lexerStringRef(string,label,elementIndex) ::= <%
|
|
<if(label)>
|
|
int <label>Start = CharIndex;<\n>
|
|
Match(<string>); <checkRuleBacktrackFailure()><\n>
|
|
int <label>StartLine<elementIndex> = Line;<\n>
|
|
int <label>StartCharPos<elementIndex> = CharPositionInLine;<\n>
|
|
<label> = new <labelType>(input, TokenTypes.Invalid, TokenChannels.Default, <label>Start, CharIndex-1);<\n>
|
|
<label>.Line = <label>StartLine<elementIndex>;<\n>
|
|
<label>.CharPositionInLine = <label>StartCharPos<elementIndex>;
|
|
<else>
|
|
Match(<string>); <checkRuleBacktrackFailure()><\n>
|
|
<endif>
|
|
%>
|
|
|
|
wildcard(token,label,elementIndex,terminalOptions) ::= <<
|
|
<if(label)>
|
|
<label>=(<labelType>)input.LT(1);<\n>
|
|
<endif>
|
|
MatchAny(input); <checkRuleBacktrackFailure()>
|
|
>>
|
|
|
|
wildcardAndListLabel(token,label,elementIndex,terminalOptions) ::= <<
|
|
<wildcard(...)>
|
|
<listLabelElem(elem=label,elemType=labelType,...)>
|
|
>>
|
|
|
|
/** Match . wildcard in lexer */
|
|
wildcardChar(label, elementIndex) ::= <<
|
|
<if(label)>
|
|
<label> = input.LA(1);<\n>
|
|
<endif>
|
|
MatchAny(); <checkRuleBacktrackFailure()>
|
|
>>
|
|
|
|
wildcardCharListLabel(label, elementIndex) ::= <<
|
|
<wildcardChar(...)>
|
|
<listLabelElem(elem=label,elemType=labelType,...)>
|
|
>>
|
|
|
|
/** Match a rule reference by invoking it possibly with arguments
|
|
* and a return value or values. The 'rule' argument was the
|
|
* target rule name, but now is type Rule, whose toString is
|
|
* same: the rule name. Now though you can access full rule
|
|
* descriptor stuff.
|
|
*/
|
|
ruleRef(rule,label,elementIndex,args,scope) ::= <<
|
|
PushFollow(Follow._<rule.name>_in_<ruleName><elementIndex>);
|
|
<if(label)><label>=<endif><if(scope)><scope:delegateName()>.<endif><rule.name; format="id">(<args; separator=", ">);
|
|
PopFollow();
|
|
<checkRuleBacktrackFailure()>
|
|
>>
|
|
|
|
/** ids+=r */
|
|
ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
|
|
<ruleRef(...)>
|
|
<listLabelElem(elem=label,elemType={<ASTLabelType>},...)>
|
|
>>
|
|
|
|
/** A lexer rule reference.
|
|
*
|
|
* The 'rule' argument was the target rule name, but now
|
|
* is type Rule, whose toString is same: the rule name.
|
|
* Now though you can access full rule descriptor stuff.
|
|
*/
|
|
lexerRuleRef(rule,label,args,elementIndex,scope) ::= <%
|
|
<if(label)>
|
|
int <label>Start<elementIndex> = CharIndex;<\n>
|
|
int <label>StartLine<elementIndex> = Line;<\n>
|
|
int <label>StartCharPos<elementIndex> = CharPositionInLine;<\n>
|
|
<if(scope)><scope:delegateName()>.<endif>m<rule.name>(<args; separator=", ">); <checkRuleBacktrackFailure()><\n>
|
|
<label> = new <labelType>(input, TokenTypes.Invalid, TokenChannels.Default, <label>Start<elementIndex>, CharIndex-1);<\n>
|
|
<label>.Line = <label>StartLine<elementIndex>;<\n>
|
|
<label>.CharPositionInLine = <label>StartCharPos<elementIndex>;
|
|
<else>
|
|
<if(scope)><scope:delegateName()>.<endif>m<rule.name>(<args; separator=", ">); <checkRuleBacktrackFailure()>
|
|
<endif>
|
|
%>
|
|
|
|
/** i+=INT in lexer */
|
|
lexerRuleRefAndListLabel(rule,label,args,elementIndex,scope) ::= <<
|
|
<lexerRuleRef(...)>
|
|
<listLabelElem(elem=label,elemType=labelType,...)>
|
|
>>
|
|
|
|
/** EOF in the lexer */
|
|
lexerMatchEOF(label,elementIndex) ::= <%
|
|
<if(label)>
|
|
int <label>Start<elementIndex> = CharIndex;<\n>
|
|
int <label>StartLine<elementIndex> = Line;<\n>
|
|
int <label>StartCharPos<elementIndex> = CharPositionInLine;<\n>
|
|
Match(EOF); <checkRuleBacktrackFailure()><\n>
|
|
<labelType> <label> = new <labelType>(input, EOF, TokenChannels.Default, <label>Start<elementIndex>, CharIndex-1);<\n>
|
|
<label>.Line = <label>StartLine<elementIndex>;<\n>
|
|
<label>.CharPositionInLine = <label>StartCharPos<elementIndex>;
|
|
<else>
|
|
Match(EOF); <checkRuleBacktrackFailure()>
|
|
<endif>
|
|
%>
|
|
|
|
// used for left-recursive rules
|
|
recRuleDefArg() ::= "int <recRuleArg()>"
|
|
recRuleArg() ::= "_p"
|
|
recRuleAltPredicate(ruleName,opPrec) ::= "<recRuleArg()> \<= <opPrec>"
|
|
recRuleSetResultAction() ::= "root_0=$<ruleName>_primary.tree;"
|
|
|
|
/** match ^(root children) in tree parser */
|
|
tree(root, actionsAfterRoot, children, nullableChildList,
|
|
enclosingTreeLevel, treeLevel) ::= <<
|
|
<root:element()>
|
|
<actionsAfterRoot:element()>
|
|
<if(nullableChildList)>
|
|
if (input.LA(1) == TokenTypes.Down)
|
|
{
|
|
Match(input, TokenTypes.Down, null); <checkRuleBacktrackFailure()>
|
|
<children:element()>
|
|
Match(input, TokenTypes.Up, null); <checkRuleBacktrackFailure()>
|
|
}
|
|
<else>
|
|
Match(input, TokenTypes.Down, null); <checkRuleBacktrackFailure()>
|
|
<children:element()>
|
|
Match(input, TokenTypes.Up, null); <checkRuleBacktrackFailure()>
|
|
<endif>
|
|
>>
|
|
|
|
/** Every predicate is used as a validating predicate (even when it is
|
|
* also hoisted into a prediction expression).
|
|
*/
|
|
validateSemanticPredicate(pred,description) ::= <<
|
|
if (!(<evalPredicate(...)>))
|
|
{
|
|
<ruleBacktrackFailure()>
|
|
throw new FailedPredicateException(input, "<ruleName>", "<description>");
|
|
}
|
|
>>
|
|
|
|
// F i x e d D F A (if-then-else)
|
|
|
|
dfaState(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= <<
|
|
int LA<decisionNumber>_<k> = input.LA(<k>);<\n>
|
|
<edges; separator="\nelse ">
|
|
else
|
|
{
|
|
<if(eotPredictsAlt)>
|
|
alt<decisionNumber> = <eotPredictsAlt>;
|
|
<else>
|
|
<ruleBacktrackFailure()>
|
|
NoViableAltException nvae = new NoViableAltException("<description>", <decisionNumber>, <stateNumber>, input, <k>);
|
|
DebugRecognitionException(nvae);
|
|
<@noViableAltException()>
|
|
throw nvae;
|
|
<endif>
|
|
}
|
|
>>
|
|
|
|
/** Same as a normal DFA state except that we don't examine lookahead
|
|
* for the bypass alternative. It delays error detection but this
|
|
* is faster, smaller, and more what people expect. For (X)? people
|
|
* expect "if ( LA(1)==X ) match(X);" and that's it.
|
|
*/
|
|
dfaOptionalBlockState(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= <<
|
|
int LA<decisionNumber>_<k> = input.LA(<k>);<\n>
|
|
<edges; separator="\nelse ">
|
|
>>
|
|
|
|
/** A DFA state that is actually the loopback decision of a closure
|
|
* loop. If end-of-token (EOT) predicts any of the targets then it
|
|
* should act like a default clause (i.e., no error can be generated).
|
|
* This is used only in the lexer so that for ('a')* on the end of a rule
|
|
* anything other than 'a' predicts exiting.
|
|
*/
|
|
dfaLoopbackState(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= <<
|
|
int LA<decisionNumber>_<k> = input.LA(<k>);<\n>
|
|
<edges; separator="\nelse "><\n>
|
|
<if(eotPredictsAlt)>
|
|
<if(!edges)>
|
|
alt<decisionNumber> = <eotPredictsAlt>;<! if no edges, don't gen ELSE !>
|
|
<else>
|
|
else
|
|
{
|
|
alt<decisionNumber> = <eotPredictsAlt>;
|
|
}<\n>
|
|
<endif>
|
|
<endif>
|
|
>>
|
|
|
|
/** An accept state indicates a unique alternative has been predicted */
|
|
dfaAcceptState(alt) ::= "alt<decisionNumber> = <alt>;"
|
|
|
|
/** A simple edge with an expression. If the expression is satisfied,
|
|
* enter to the target state. To handle gated productions, we may
|
|
* have to evaluate some predicates for this edge.
|
|
*/
|
|
dfaEdge(labelExpr, targetState, predicates) ::= <<
|
|
if ((<labelExpr>)<if(predicates)> && (<predicates>)<endif>)
|
|
{
|
|
<targetState>
|
|
}
|
|
>>
|
|
|
|
// F i x e d D F A (switch case)
|
|
|
|
/** A DFA state where a SWITCH may be generated. The code generator
|
|
* decides if this is possible: CodeGenerator.canGenerateSwitch().
|
|
*/
|
|
dfaStateSwitch(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= <<
|
|
switch (input.LA(<k>))
|
|
{
|
|
<edges; separator="\n">
|
|
default:
|
|
<if(eotPredictsAlt)>
|
|
alt<decisionNumber>=<eotPredictsAlt>;
|
|
break;<\n>
|
|
<else>
|
|
{
|
|
<ruleBacktrackFailure()>
|
|
NoViableAltException nvae = new NoViableAltException("<description>", <decisionNumber>, <stateNumber>, input, <k>);
|
|
DebugRecognitionException(nvae);
|
|
<@noViableAltException()>
|
|
throw nvae;
|
|
}
|
|
<endif>
|
|
}<\n>
|
|
>>
|
|
|
|
dfaOptionalBlockStateSwitch(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= <<
|
|
switch (input.LA(<k>))
|
|
{
|
|
<edges; separator="\n">
|
|
}<\n>
|
|
>>
|
|
|
|
dfaLoopbackStateSwitch(k, edges,eotPredictsAlt,description,stateNumber,semPredState) ::= <<
|
|
switch (input.LA(<k>))
|
|
{
|
|
<edges; separator="\n">
|
|
<if(eotPredictsAlt)>
|
|
default:
|
|
alt<decisionNumber>=<eotPredictsAlt>;
|
|
break;<\n>
|
|
<endif>
|
|
}<\n>
|
|
>>
|
|
|
|
dfaEdgeSwitch(labels, targetState) ::= <<
|
|
<labels:{it|case <it>:}; separator="\n">
|
|
{
|
|
<targetState>
|
|
}
|
|
break;
|
|
>>
|
|
|
|
// C y c l i c D F A
|
|
|
|
/** The code to initiate execution of a cyclic DFA; this is used
|
|
* in the rule to predict an alt just like the fixed DFA case.
|
|
* The <name> attribute is inherited via the parser, lexer, ...
|
|
*/
|
|
dfaDecision(decisionNumber,description) ::= <<
|
|
try
|
|
{
|
|
alt<decisionNumber> = dfa<decisionNumber>.Predict(input);
|
|
}
|
|
catch (NoViableAltException nvae)
|
|
{
|
|
DebugRecognitionException(nvae);
|
|
throw;
|
|
}
|
|
>>
|
|
|
|
/* Dump DFA tables as run-length-encoded Strings of octal values.
|
|
* Can't use hex as compiler translates them before compilation.
|
|
* These strings are split into multiple, concatenated strings.
|
|
* Java puts them back together at compile time thankfully.
|
|
* Java cannot handle large static arrays, so we're stuck with this
|
|
* encode/decode approach. See analysis and runtime DFA for
|
|
* the encoding methods.
|
|
*/
|
|
cyclicDFA(dfa) ::= <<
|
|
private class DFA<dfa.decisionNumber> : DFA
|
|
{
|
|
private const string DFA<dfa.decisionNumber>_eotS =
|
|
"<dfa.javaCompressedEOT; wrap="\"+\n\t\t\"">";
|
|
private const string DFA<dfa.decisionNumber>_eofS =
|
|
"<dfa.javaCompressedEOF; wrap="\"+\n\t\t\"">";
|
|
private const string DFA<dfa.decisionNumber>_minS =
|
|
"<dfa.javaCompressedMin; wrap="\"+\n\t\t\"">";
|
|
private const string DFA<dfa.decisionNumber>_maxS =
|
|
"<dfa.javaCompressedMax; wrap="\"+\n\t\t\"">";
|
|
private const string DFA<dfa.decisionNumber>_acceptS =
|
|
"<dfa.javaCompressedAccept; wrap="\"+\n\t\t\"">";
|
|
private const string DFA<dfa.decisionNumber>_specialS =
|
|
"<dfa.javaCompressedSpecial; wrap="\"+\n\t\t\"">}>";
|
|
private static readonly string[] DFA<dfa.decisionNumber>_transitionS =
|
|
{
|
|
<dfa.javaCompressedTransition:{s|"<s; wrap="\"+\n\"">"}; separator=",\n">
|
|
};
|
|
|
|
private static readonly short[] DFA<dfa.decisionNumber>_eot = DFA.UnpackEncodedString(DFA<dfa.decisionNumber>_eotS);
|
|
private static readonly short[] DFA<dfa.decisionNumber>_eof = DFA.UnpackEncodedString(DFA<dfa.decisionNumber>_eofS);
|
|
private static readonly char[] DFA<dfa.decisionNumber>_min = DFA.UnpackEncodedStringToUnsignedChars(DFA<dfa.decisionNumber>_minS);
|
|
private static readonly char[] DFA<dfa.decisionNumber>_max = DFA.UnpackEncodedStringToUnsignedChars(DFA<dfa.decisionNumber>_maxS);
|
|
private static readonly short[] DFA<dfa.decisionNumber>_accept = DFA.UnpackEncodedString(DFA<dfa.decisionNumber>_acceptS);
|
|
private static readonly short[] DFA<dfa.decisionNumber>_special = DFA.UnpackEncodedString(DFA<dfa.decisionNumber>_specialS);
|
|
private static readonly short[][] DFA<dfa.decisionNumber>_transition;
|
|
|
|
static DFA<dfa.decisionNumber>()
|
|
{
|
|
int numStates = DFA<dfa.decisionNumber>_transitionS.Length;
|
|
DFA<dfa.decisionNumber>_transition = new short[numStates][];
|
|
for ( int i=0; i \< numStates; i++ )
|
|
{
|
|
DFA<dfa.decisionNumber>_transition[i] = DFA.UnpackEncodedString(DFA<dfa.decisionNumber>_transitionS[i]);
|
|
}
|
|
}
|
|
|
|
public DFA<dfa.decisionNumber>( BaseRecognizer recognizer<if(dfa.specialStateSTs)>, SpecialStateTransitionHandler specialStateTransition<endif> )
|
|
<if(dfa.specialStateSTs)>
|
|
: base(specialStateTransition)
|
|
<endif>
|
|
{
|
|
this.recognizer = recognizer;
|
|
this.decisionNumber = <dfa.decisionNumber>;
|
|
this.eot = DFA<dfa.decisionNumber>_eot;
|
|
this.eof = DFA<dfa.decisionNumber>_eof;
|
|
this.min = DFA<dfa.decisionNumber>_min;
|
|
this.max = DFA<dfa.decisionNumber>_max;
|
|
this.accept = DFA<dfa.decisionNumber>_accept;
|
|
this.special = DFA<dfa.decisionNumber>_special;
|
|
this.transition = DFA<dfa.decisionNumber>_transition;
|
|
}
|
|
|
|
public override string Description { get { return "<dfa.description>"; } }
|
|
|
|
public override void Error(NoViableAltException nvae)
|
|
{
|
|
DebugRecognitionException(nvae);
|
|
}
|
|
}<\n>
|
|
<if(dfa.specialStateSTs)>
|
|
private int SpecialStateTransition<dfa.decisionNumber>(DFA dfa, int s, IIntStream _input)<! throws NoViableAltException!>
|
|
{
|
|
<if(LEXER)>
|
|
IIntStream input = _input;
|
|
<endif>
|
|
<if(PARSER)>
|
|
ITokenStream input = (ITokenStream)_input;
|
|
<endif>
|
|
<if(TREE_PARSER)>
|
|
ITreeNodeStream input = (ITreeNodeStream)_input;
|
|
<endif>
|
|
int _s = s;
|
|
s = -1;
|
|
<! pull these outside the switch cases to save space on locals !>
|
|
int LA<dfa.decisionNumber>_1 = input.LA(1);
|
|
int index<dfa.decisionNumber>_1 = input.Index;
|
|
switch (_s)
|
|
{
|
|
<dfa.specialStateSTs:{state |case <i0>:<! compressed special state numbers 0..n-1 !>
|
|
<state>}; separator="\n">
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (s >= 0)
|
|
return s;
|
|
|
|
<if(backtracking)>
|
|
if (state.backtracking > 0) {state.failed=true; return -1;}
|
|
<endif>
|
|
NoViableAltException nvae = new NoViableAltException(dfa.Description, <dfa.decisionNumber>, _s, input);
|
|
dfa.Error(nvae);
|
|
throw nvae;
|
|
}
|
|
<endif>
|
|
>>
|
|
|
|
/** A state in a cyclic DFA; it's a special state and part of a big switch on
|
|
* state.
|
|
*/
|
|
cyclicDFAState(decisionNumber,stateNumber,edges,needErrorClause,semPredState) ::= <<
|
|
{
|
|
<if(semPredState)>
|
|
<! get next lookahead symbol to test edges, then rewind !>
|
|
input.Rewind();
|
|
<endif>
|
|
<edges; separator="\nelse ">
|
|
<if(semPredState)>
|
|
<! return input cursor to state before we rewound !>
|
|
input.Seek(index<decisionNumber>_1);
|
|
<endif>
|
|
break;
|
|
}
|
|
>>
|
|
|
|
/** Just like a fixed DFA edge, test the lookahead and indicate what
|
|
* state to jump to next if successful.
|
|
*/
|
|
cyclicDFAEdge(labelExpr, targetStateNumber, edgeNumber, predicates) ::= <<
|
|
if ((<labelExpr>)<if(predicates)> && (<predicates>)<endif>) {s = <targetStateNumber>;}<\n>
|
|
>>
|
|
|
|
/** An edge pointing at end-of-token; essentially matches any char;
|
|
* always jump to the target.
|
|
*/
|
|
eotDFAEdge(targetStateNumber,edgeNumber, predicates) ::= <<
|
|
s = <targetStateNumber>;<\n>
|
|
>>
|
|
|
|
|
|
// D F A E X P R E S S I O N S
|
|
|
|
andPredicates(left,right) ::= "(<left>&&<right>)"
|
|
|
|
orPredicates(operands) ::= "(<first(operands)><rest(operands):{o | ||<o>}>)"
|
|
|
|
notPredicate(pred) ::= "!(<evalPredicate(...)>)"
|
|
|
|
evalPredicate(pred,description) ::= "(<pred>)"
|
|
|
|
evalSynPredicate(pred,description) ::= "EvaluatePredicate(<pred>_fragment)"
|
|
|
|
lookaheadTest(atom,k,atomAsInt) ::= "LA<decisionNumber>_<k>==<atom>"
|
|
|
|
/** Sometimes a lookahead test cannot assume that LA(k) is in a temp variable
|
|
* somewhere. Must ask for the lookahead directly.
|
|
*/
|
|
isolatedLookaheadTest(atom,k,atomAsInt) ::= "input.LA(<k>)==<atom>"
|
|
|
|
lookaheadRangeTest(lower,upper,k,rangeNumber,lowerAsInt,upperAsInt) ::= <%
|
|
(LA<decisionNumber>_<k><ge()><lower> && LA<decisionNumber>_<k><le()><upper>)
|
|
%>
|
|
|
|
isolatedLookaheadRangeTest(lower,upper,k,rangeNumber,lowerAsInt,upperAsInt) ::= "(input.LA(<k>)<ge()><lower> && input.LA(<k>)<le()><upper>)"
|
|
|
|
le() ::= "\<="
|
|
ge() ::= ">="
|
|
|
|
setTest(ranges) ::= <<
|
|
<ranges; separator="||">
|
|
>>
|
|
|
|
// A T T R I B U T E S
|
|
|
|
attributeScope(scope) ::= <<
|
|
<if(scope.attributes)>
|
|
protected sealed partial class <scope.name>_scope
|
|
{
|
|
<scope.attributes:{it|public <it.decl>;}; separator="\n">
|
|
|
|
public <scope.name>_scope(<grammar.recognizerName> grammar) { OnCreated(grammar); }
|
|
partial void OnCreated(<grammar.recognizerName> grammar);
|
|
}
|
|
<if(scope.actions.scopeinit)>
|
|
protected void <scope.name>_scopeInit( <scope.name>_scope scope )
|
|
{
|
|
<scope.actions.scopeinit>
|
|
}
|
|
<else>
|
|
partial void <scope.name>_scopeInit( <scope.name>_scope scope );
|
|
<endif>
|
|
<if(scope.actions.scopeafter)>
|
|
protected void <scope.name>_scopeAfter( <scope.name>_scope scope )
|
|
{
|
|
<scope.actions.scopeafter>
|
|
}
|
|
<else>
|
|
partial void <scope.name>_scopeAfter( <scope.name>_scope scope );
|
|
<endif>
|
|
protected readonly ListStack\<<scope.name>_scope\> <scope.name>_stack = new ListStack\<<scope.name>_scope\>();
|
|
<endif>
|
|
>>
|
|
|
|
globalAttributeScope(scope) ::= <<
|
|
<attributeScope(...)>
|
|
>>
|
|
|
|
ruleAttributeScope(scope) ::= <<
|
|
<attributeScope(...)>
|
|
>>
|
|
|
|
returnStructName(it) ::= "<it.name>_return"
|
|
|
|
returnType(ruleDescriptor) ::= <%
|
|
<if(ruleDescriptor.returnScope.attributes && ruleDescriptor.hasMultipleReturnValues)>
|
|
<ruleDescriptor.grammar.recognizerName>.<ruleDescriptor:returnStructName()>
|
|
<elseif(ruleDescriptor.hasMultipleReturnValues)>
|
|
<ruleReturnBaseType()>
|
|
<elseif(ruleDescriptor.hasSingleReturnValue)>
|
|
<ruleDescriptor.singleValueReturnType>
|
|
<else>
|
|
void
|
|
<endif>
|
|
%>
|
|
|
|
/** Generate the C# type associated with a single or multiple return
|
|
* values.
|
|
*/
|
|
ruleLabelType(referencedRule) ::= <%
|
|
<if(referencedRule.returnScope.attributes&&referencedRule.hasMultipleReturnValues)>
|
|
<referencedRule.grammar.recognizerName>.<referencedRule:returnStructName()>
|
|
<elseif(referencedRule.hasMultipleReturnValues)>
|
|
<ruleReturnBaseType()>
|
|
<elseif(referencedRule.hasSingleReturnValue)>
|
|
<referencedRule.singleValueReturnType>
|
|
<else>
|
|
void
|
|
<endif>
|
|
%>
|
|
|
|
delegateName(it) ::= <<
|
|
<if(it.label)><it.label><else>g<it.name><endif>
|
|
>>
|
|
|
|
/** Using a type to init value map, try to init a type; if not in table
|
|
* must be an object, default value is "null".
|
|
*/
|
|
initValue(typeName) ::= <<
|
|
default(<typeName>)
|
|
>>
|
|
|
|
/** Define a rule label including default value */
|
|
ruleLabelDef(label) ::= <%
|
|
<ruleLabelType(label.referencedRule)> <label.label.text> = <initValue(ruleLabelType(label.referencedRule))>;
|
|
%>
|
|
|
|
/** Define a return struct for a rule if the code needs to access its
|
|
* start/stop tokens, tree stuff, attributes, ... Leave a hole for
|
|
* subgroups to stick in members.
|
|
*/
|
|
returnScope(scope) ::= <<
|
|
<if(scope.attributes && ruleDescriptor.hasMultipleReturnValues)>
|
|
<returnScopeModifier(grammar=grammar,ruleDescriptor=ruleDescriptor)> sealed partial class <ruleDescriptor:returnStructName()> : <ruleReturnBaseType()><@ruleReturnInterfaces()>
|
|
{
|
|
<scope.attributes:{it|public <it.decl>;}; separator="\n">
|
|
<@ruleReturnMembers()>
|
|
}
|
|
<endif>
|
|
>>
|
|
|
|
ruleReturnBaseType() ::= <%
|
|
<if(TREE_PARSER)>Tree<else>Parser<endif>RuleReturnScope\<<labelType>>
|
|
%>
|
|
|
|
@returnScope.ruleReturnMembers() ::= <<
|
|
public <ruleDescriptor:returnStructName()>(<grammar.recognizerName> grammar) {OnCreated(grammar);}
|
|
partial void OnCreated(<grammar.recognizerName> grammar);
|
|
>>
|
|
|
|
parameterScope(scope) ::= <<
|
|
<scope.attributes:{it|<it.decl>}; separator=", ">
|
|
>>
|
|
|
|
parameterAttributeRef(attr) ::= <<
|
|
<attr.name; format="id">
|
|
>>
|
|
|
|
parameterSetAttributeRef(attr,expr) ::= <<
|
|
<attr.name; format="id"> =<expr>;
|
|
>>
|
|
|
|
scopeAttributeRef(scope,attr,index,negIndex) ::= <%
|
|
<if(negIndex)>
|
|
<scope>_stack[<scope>_stack.Count - <negIndex> - 1].<attr.name; format="id">
|
|
<else>
|
|
<if(index)>
|
|
<scope>_stack[<index>].<attr.name; format="id">
|
|
<else>
|
|
<scope>_stack.Peek().<attr.name; format="id">
|
|
<endif>
|
|
<endif>
|
|
%>
|
|
|
|
scopeSetAttributeRef(scope,attr,expr,index,negIndex) ::= <%
|
|
<if(negIndex)>
|
|
<scope>_stack[<scope>_stack.Count - <negIndex> - 1].<attr.name; format="id"> = <expr>;
|
|
<else>
|
|
<if(index)>
|
|
<scope>_stack[<index>].<attr.name; format="id"> = <expr>;
|
|
<else>
|
|
<scope>_stack.Peek().<attr.name; format="id"> = <expr>;
|
|
<endif>
|
|
<endif>
|
|
%>
|
|
|
|
/** $x is either global scope or x is rule with dynamic scope; refers
|
|
* to stack itself not top of stack. This is useful for predicates
|
|
* like {$function.Count>0 && $function::name.Equals("foo")}?
|
|
*/
|
|
isolatedDynamicScopeRef(scope) ::= "<scope>_stack"
|
|
|
|
/** reference an attribute of rule; might only have single return value */
|
|
ruleLabelRef(referencedRule,scope,attr) ::= <%
|
|
<if(referencedRule.hasMultipleReturnValues)>
|
|
(<scope>!=null?<scope>.<attr.name; format="id">:<initValue(attr.type)>)
|
|
<else>
|
|
<scope>
|
|
<endif>
|
|
%>
|
|
|
|
returnAttributeRef(ruleDescriptor,attr) ::= <%
|
|
<if(ruleDescriptor.hasMultipleReturnValues)>
|
|
retval.<attr.name; format="id">
|
|
<else>
|
|
<attr.name; format="id">
|
|
<endif>
|
|
%>
|
|
|
|
returnSetAttributeRef(ruleDescriptor,attr,expr) ::= <%
|
|
<if(ruleDescriptor.hasMultipleReturnValues)>
|
|
retval.<attr.name; format="id"> =<expr>;
|
|
<else>
|
|
<attr.name; format="id"> =<expr>;
|
|
<endif>
|
|
%>
|
|
|
|
/** How to translate $tokenLabel */
|
|
tokenLabelRef(label) ::= "<label>"
|
|
|
|
/** ids+=ID {$ids} or e+=expr {$e} */
|
|
listLabelRef(label) ::= "list_<label>"
|
|
|
|
|
|
// not sure the next are the right approach
|
|
|
|
tokenLabelPropertyRef_text(scope,attr) ::= "(<scope>!=null?<scope>.Text:null)"
|
|
tokenLabelPropertyRef_type(scope,attr) ::= "(<scope>!=null?<scope>.Type:0)"
|
|
tokenLabelPropertyRef_line(scope,attr) ::= "(<scope>!=null?<scope>.Line:0)"
|
|
tokenLabelPropertyRef_pos(scope,attr) ::= "(<scope>!=null?<scope>.CharPositionInLine:0)"
|
|
tokenLabelPropertyRef_channel(scope,attr) ::= "(<scope>!=null?<scope>.Channel:0)"
|
|
tokenLabelPropertyRef_index(scope,attr) ::= "(<scope>!=null?<scope>.TokenIndex:0)"
|
|
tokenLabelPropertyRef_tree(scope,attr) ::= "<scope>_tree"
|
|
tokenLabelPropertyRef_int(scope,attr) ::= "(<scope>!=null?int.Parse(<scope>.Text):0)"
|
|
|
|
ruleLabelPropertyRef_start(scope,attr) ::= "(<scope>!=null?((<labelType>)<scope>.Start):default(<labelType>))"
|
|
ruleLabelPropertyRef_stop(scope,attr) ::= "(<scope>!=null?((<labelType>)<scope>.Stop):default(<labelType>))"
|
|
ruleLabelPropertyRef_tree(scope,attr) ::= "(<scope>!=null?((<ASTLabelType>)<scope>.Tree):default(<ASTLabelType>))"
|
|
ruleLabelPropertyRef_text(scope,attr) ::= <%
|
|
<if(TREE_PARSER)>
|
|
(<scope>!=null?(input.TokenStream.ToString(
|
|
input.TreeAdaptor.GetTokenStartIndex(<scope>.Start),
|
|
input.TreeAdaptor.GetTokenStopIndex(<scope>.Start))):null)
|
|
<else>
|
|
(<scope>!=null?input.ToString(<scope>.Start,<scope>.Stop):null)
|
|
<endif>
|
|
%>
|
|
|
|
ruleLabelPropertyRef_st(scope,attr) ::= "(<scope>!=null?<scope>.Template:null)"
|
|
|
|
/** Isolated $RULE ref ok in lexer as it's a Token */
|
|
lexerRuleLabel(label) ::= "<label>"
|
|
|
|
lexerRuleLabelPropertyRef_type(scope,attr) ::=
|
|
"(<scope>!=null?<scope>.Type:0)"
|
|
|
|
lexerRuleLabelPropertyRef_line(scope,attr) ::=
|
|
"(<scope>!=null?<scope>.Line:0)"
|
|
|
|
lexerRuleLabelPropertyRef_pos(scope,attr) ::=
|
|
"(<scope>!=null?<scope>.CharPositionInLine:-1)"
|
|
|
|
lexerRuleLabelPropertyRef_channel(scope,attr) ::=
|
|
"(<scope>!=null?<scope>.Channel:0)"
|
|
|
|
lexerRuleLabelPropertyRef_index(scope,attr) ::=
|
|
"(<scope>!=null?<scope>.TokenIndex:0)"
|
|
|
|
lexerRuleLabelPropertyRef_text(scope,attr) ::=
|
|
"(<scope>!=null?<scope>.Text:null)"
|
|
|
|
lexerRuleLabelPropertyRef_int(scope,attr) ::=
|
|
"(<scope>!=null?int.Parse(<scope>.Text):0)"
|
|
|
|
// Somebody may ref $template or $tree or $stop within a rule:
|
|
rulePropertyRef_start(scope,attr) ::= "retval.Start"
|
|
rulePropertyRef_stop(scope,attr) ::= "retval.Stop"
|
|
rulePropertyRef_tree(scope,attr) ::= "retval.Tree"
|
|
rulePropertyRef_text(scope,attr) ::= <%
|
|
<if(TREE_PARSER)>
|
|
input.TokenStream.ToString(
|
|
input.TreeAdaptor.GetTokenStartIndex(retval.Start),
|
|
input.TreeAdaptor.GetTokenStopIndex(retval.Start))
|
|
<else>
|
|
input.ToString(retval.Start,input.LT(-1))
|
|
<endif>
|
|
%>
|
|
rulePropertyRef_st(scope,attr) ::= "retval.Template"
|
|
|
|
lexerRulePropertyRef_text(scope,attr) ::= "Text"
|
|
lexerRulePropertyRef_type(scope,attr) ::= "_type"
|
|
lexerRulePropertyRef_line(scope,attr) ::= "state.tokenStartLine"
|
|
lexerRulePropertyRef_pos(scope,attr) ::= "state.tokenStartCharPositionInLine"
|
|
lexerRulePropertyRef_index(scope,attr) ::= "-1" // undefined token index in lexer
|
|
lexerRulePropertyRef_channel(scope,attr) ::= "_channel"
|
|
lexerRulePropertyRef_start(scope,attr) ::= "state.tokenStartCharIndex"
|
|
lexerRulePropertyRef_stop(scope,attr) ::= "(CharIndex-1)"
|
|
lexerRulePropertyRef_int(scope,attr) ::= "int.Parse(<scope>.Text)"
|
|
|
|
// setting $st and $tree is allowed in local rule. everything else
|
|
// is flagged as error
|
|
ruleSetPropertyRef_tree(scope,attr,expr) ::= "retval.Tree = <expr>;"
|
|
ruleSetPropertyRef_st(scope,attr,expr) ::= "retval.Template =<expr>;"
|
|
|
|
/** How to execute an action (only when not backtracking) */
|
|
execAction(action) ::= <%
|
|
<if(backtracking)>
|
|
if (<actions.(actionScope).synpredgate>)<\n>
|
|
{<\n>
|
|
<@indentedAction()><\n>
|
|
}
|
|
<else>
|
|
<action>
|
|
<endif>
|
|
%>
|
|
|
|
@execAction.indentedAction() ::= <<
|
|
<action>
|
|
>>
|
|
|
|
/** How to always execute an action even when backtracking */
|
|
execForcedAction(action) ::= "<action>"
|
|
|
|
// M I S C (properties, etc...)
|
|
|
|
bitset(name, words64) ::= <<
|
|
public static readonly BitSet <name> = new BitSet(new ulong[]{<words64:{it|<it>UL};separator=",">});
|
|
>>
|
|
|
|
codeFileExtension() ::= ".cs"
|
|
|
|
true_value() ::= "true"
|
|
false_value() ::= "false"
|