blob: 71670396a4b13cbdc9e8946177aa4a349b1b0bfa [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2012 E.D.Willink and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*
* </copyright>
*/
/*
http://lampwww.epfl.ch/teaching/archive/compilation-ssc/2000/part4/parsing/node3.html
For building parsers (especially bottom-up) a BNF grammar is often better, than EBNF. But it's easy to convert an XBNF Grammar to XBNF:
Convert every repetition { E } to a fresh non-terminal X and add
X = $\epsilon$ | X E.
Convert every option [ E ] to a fresh non-terminal X and add
X = $\epsilon$ | E.
(We can convert X = A [ E ] B. to X = A E B | A B.)
Convert every group ( E ) to a fresh non-terminal X and add
X = E.
We can even do away with alternatives by having several productions with the same non-terminal.
X = E | E'. becomes X = E. X = E'.
---
As above, also normalizse so that the output is a
rule comprising
-- a disjunction of
-- one or more conjunctions comprising
-- zero or more elements.
Additional rules for multiplicities and alternatives are created as sub-rules, some
of which may be inlined by a subsequent inline transformation.
*/
modeltype ECORE uses 'http://www.eclipse.org/emf/2002/Ecore';
modeltype XBNF uses 'http://www.eclipse.org/ocl/XBNF';
modeltype XBNFwc uses 'http://www.eclipse.org/ocl/XBNFwithCardinality';
transformation normalize(in xtext : XBNFwc, out XBNF);
main() {
xtext.rootObjects()[XBNF::Syntax]->map syntax2syntax();
}
mapping XBNF::Syntax::syntax2syntax() : XBNF::Syntax {
var allRules : Sequence(TypedRule) = self.grammars->collect(rules->sortedBy(name));
var firstRules : OrderedSet(TypedRule) = allRules->collect(r1 | allRules->select(r2 | r1.name = r2.name)->first())->asOrderedSet();
name := self.name;
grammars := Sequence { self.map grammars2lexerGrammar(firstRules), self.map grammars2parserGrammar(firstRules) };
}
--mapping XBNF::Grammar::grammar2grammar() : XBNF::Grammar
--disjuncts
--LexerGrammar::lexerGrammar2grammar,
--ParserGrammar::parserGrammar2grammar
--{}
---------------------------------------------------------------------------------------
-- Copy the lexer rules
---------------------------------------------------------------------------------------
mapping XBNF::Syntax::grammars2lexerGrammar(firstRules : Set(TypedRule)) : XBNF::LexerGrammar {
name := self.name;
rules := self.grammars.rules->select(oclIsKindOf(TerminalRule)).oclAsType(TerminalRule)->map terminalRule2rule(firstRules);
goals := self.grammars.goals.resolveone(TypedRule);
}
--mapping XBNF::LexerGrammar::lexerGrammar2grammar() : XBNF::LexerGrammar {
-- name := self.name;
-- rules := self.rules->select(oclIsKindOf(TerminalRule)).oclAsType(TerminalRule)->map terminalRule2rule();
-- goals := self.goals.resolveone(TypedRule);
--}
mapping XBNF::TerminalRule::terminalRule2rule(firstRules : Set(TypedRule)) : XBNF::TerminalRule
{
var subRules : List(XBNF::UntypedRule) = List{};
name := self.name;
debug := self.debug;
type := self.type;
element := self.element.map element2element(self.name, subRules, self, firstRules);
subrules := subRules->iterate(r; acc : Sequence(XBNF::UntypedRule) = Sequence{} | acc->append(r));
}
/*
mapping XBNF::AbstractElement::element2lexerElement() : XBNF::AbstractElement
disjuncts
Alternatives::alternatives2lexerElement,
CharacterRange::keyword2lexerElement,
Keyword::keyword2lexerElement,
NegatedToken::negatedToken2lexerElement,
OneOrMore::oneOrMore2lexerElement,
RuleCall::ruleCall2lexerElement,
Succession::succession2lexerElement,
UntilToken::untilToken2lexerElement,
Wildcard::wildcard2lexerElement,
ZeroOrMore::zeroOrMore2lexerElement,
ZeroOrOne::zeroOrOne2lexerElement,
AbstractElement::element2lexerElement_default
{}
mapping XBNF::AbstractElement::element2lexerElement_default() : XBNF::Wildcard {
debug := 'default';
}
mapping XBNFwc::Alternatives::alternatives2lexerElement() : XBNFwc::Alternatives {
debug := self.debug;
elements := self.elements->map element2lexerElement();
}
mapping XBNF::CharacterRange::keyword2lexerElement() : XBNF::CharacterRange {
debug := self.debug;
left := self.left;
right := self.right;
}
mapping XBNF::Keyword::keyword2lexerElement() : XBNF::Keyword {
debug := self.debug;
value := self.value;
}
mapping XBNF::NegatedToken::negatedToken2lexerElement() : XBNF::UntilToken {
debug := self.debug;
terminal := self.terminal.map element2lexerElement();
}
mapping XBNFwc::OneOrMore::oneOrMore2lexerElement() : XBNFwc::Succession {
debug := self.debug;
elements := self.elements->map element2lexerElement();
}
mapping XBNF::RuleCall::ruleCall2lexerElement() : XBNF::RuleCall {
debug := self.rule.name;
rule := self.rule.late resolveone(XBNF::AbstractRule);
}
mapping XBNFwc::Succession::succession2lexerElement() : XBNFwc::Succession {
debug := self.debug;
elements := self.elements->map element2lexerElement();
}
mapping XBNF::UntilToken::untilToken2lexerElement() : XBNF::UntilToken {
debug := self.debug;
terminal := self.terminal.map element2lexerElement();
}
mapping XBNF::Wildcard::wildcard2lexerElement() : XBNF::Wildcard {
debug := self.debug;
}
mapping XBNFwc::ZeroOrMore::zeroOrMore2lexerElement() : XBNFwc::Succession {
debug := self.debug;
elements := self.elements->map element2lexerElement();
}
mapping XBNFwc::ZeroOrOne::zeroOrOne2lexerElement() : XBNFwc::Succession {
debug := self.debug;
elements := self.elements->map element2lexerElement();
}
*/
---------------------------------------------------------------------------------------
-- Create the extra parser rules for XBNF compounds
---------------------------------------------------------------------------------------
mapping XBNF::Syntax::grammars2parserGrammar(firstRules : Set(TypedRule)) : XBNF::ParserGrammar {
name := self.name;
-- var parserRules : Sequence(ParserRule) = self.grammars.rules->asSequence()->select(oclIsKindOf(ParserRule)).oclAsType(ParserRule);
-- var parserRuleNames : Set(String) = parserRules.name->asSet()->sortedBy(n | n);
-- rules := parserRuleNames->iterate(n; acc : OrderedSet(ParserRule) = Set{} |
-- let firstRule : ParserRule = parserRules->select(name = n)->first() in
-- let mappedRule : ParserRule = firstRule.map parserRule2rule() in
-- acc->append(mappedRule));
var parserRules : Sequence(ParserRule) = self.grammars.rules->select(oclIsKindOf(ParserRule)).oclAsType(ParserRule);
var parserRuleNames : OrderedSet(String) = parserRules.name->asSet()->sortedBy(n | n);
var sortedParserRules : Sequence(ParserRule) = parserRules->sortedBy(name);
rules := parserRuleNames->iterate(prn; acc : OrderedSet(ParserRule) = OrderedSet{} |
let pr : ParserRule = parserRules->select(name = prn)->any(true) in acc->append(pr.map parserRule2rule(firstRules)));
-- rules := sortedParserRules->iterate(pr; acc : Sequence(ParserRule) = Sequence{} | acc->append(pr.map parserRule2rule()));
goals := self.grammars->select(oclIsKindOf(ParserGrammar)).goals->first().resolveone(TypedRule);
}
--mapping XBNF::ParserGrammar::parserGrammar2grammar() : XBNF::ParserGrammar {
-- name := self.name;
-- var parserRules : Sequence(ParserRule) = self.rules->select(oclIsKindOf(ParserRule)).oclAsType(ParserRule)->sortedBy(name);
-- rules := parserRules->map parserRule2rule();
-- goals := self.goals.resolveone(TypedRule);
--}
mapping XBNF::ParserRule::parserRule2rule(firstRules : Set(TypedRule)) : XBNF::ParserRule
{
var subRules : List(XBNF::UntypedRule) = List{};
var theElement : AbstractElement = self.element.map element2element(self.name, subRules, self, firstRules);
var disjunction : Disjunction =
if theElement.oclIsKindOf(Disjunction)
then theElement.oclAsType(Disjunction)
else object Disjunction {
conjunctions := Sequence {
if theElement.oclIsKindOf(Conjunction)
then theElement.oclAsType(Conjunction)
else object Conjunction {
elements := theElement->asSequence();
}
endif
};
}
endif;
name := self.name;
debug := self.debug;
type := self.type;
element := disjunction;
subrules := subRules->iterate(r; acc : Sequence(XBNF::UntypedRule) = Sequence{} | acc->append(r));
}
mapping XBNF::AbstractElement::element2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement
disjuncts
ActionAssignment::actionAssignment2element,
Alternatives::alternativesAtRoot2element,
Alternatives::alternativesNested2element,
CharacterRange::characterRange2element,
KeywordAssignment::keywordAssignment2element,
Keyword::keyword2element,
NegatedToken::negatedToken2element,
OneOrMore::oneOrMore2element,
RuleCallAssignment::ruleCallAssignment2element,
RuleCall::ruleCall2element,
Succession::succession2element,
UntilToken::untilToken2element,
Wildcard::wildcard2element,
ZeroOrMore::zeroOrMore2element,
ZeroOrOne::zeroOrOne2element,
AbstractElement::element2element_default
{}
mapping XBNF::AbstractElement::element2element_default(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::Wildcard {
debug := 'default';
}
mapping XBNF::ActionAssignment::actionAssignment2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::ActionAssignment {
debug := self.debug;
feature := self.feature;
operator := self.operator;
type := self.type;
}
mapping XBNFwc::Alternatives::alternativesAtRoot2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::Disjunction
when { self.parentRule <> null }
{
debug := self.debug;
conjunctions := self.elements->iterate(e; acc : Sequence(Conjunction) = Sequence {} |
acc->append(object Conjunction {
elements := e.succession(Sequence{}, e)->map element2element(parentRule, subRules, disambiguator, firstRules)
}));
}
mapping XBNFwc::Alternatives::alternativesNested2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::RuleCall
{
var me : Alternatives = self;
var alternatives : Sequence(AbstractElement) = self.elements;
var oneRule : XBNF::UntypedRule = object UntypedRule {
element := object Disjunction {
debug := '1 : ' + alternatives->size().toString();
conjunctions := alternatives->iterate(e; acc : Sequence(Conjunction) = Sequence{} |
acc->append(object Conjunction {
elements := e.succession(Sequence{}, e)->map element2element(parentRule, subRules, e, firstRules);
}));
};
name := parentRule + '_' + subRules->size().toString();
};
subRules->add(oneRule);
debug := oneRule.name;
referredRule := oneRule;
}
mapping XBNF::CharacterRange::characterRange2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::CharacterRange {
debug := self.debug;
left := self.left;
right := self.right;
}
mapping XBNF::Keyword::keyword2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::Keyword {
debug := self.debug;
value := self.value;
}
mapping XBNF::KeywordAssignment::keywordAssignment2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::KeywordAssignment {
debug := self.debug;
feature := self.feature;
operator := self.operator;
value := self.value;
}
mapping XBNF::NegatedToken::negatedToken2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::UntilToken {
debug := self.debug;
terminal := self.terminal.map element2element(parentRule, subRules, disambiguator, firstRules);
}
mapping XBNFwc::OneOrMore::oneOrMore2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::RuleCall {
var oneRule : XBNF::UntypedRule = self.map element2subRule(parentRule, subRules, disambiguator, firstRules);
subRules->add(oneRule);
var oneOrMoreRule : XBNF::UntypedRule = oneRule.map rule2oneOrMoreSubRule(parentRule, subRules);
subRules->add(oneOrMoreRule);
debug := oneOrMoreRule.name;
referredRule := oneOrMoreRule;
}
mapping XBNF::RuleCall::ruleCall2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::RuleCall {
debug := self.debug;
referredRule := firstRules->select(r | r.name = self.referredRule.name)->any(true).late resolveone(XBNF::AbstractRule);
}
mapping XBNF::RuleCallAssignment::ruleCallAssignment2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::RuleCallAssignment {
-- var syntax : Syntax = self.referredRule.grammar.syntax;
debug := self.debug;
feature := self.feature;
operator := self.operator;
referredRule := firstRules->select(r | r.name = self.referredRule.name)->any(true).late resolveone(XBNF::AbstractRule);
}
mapping XBNFwc::Succession::succession2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::Conjunction {
debug := self.debug;
elements := self.succession(Sequence{}, self)->map element2element(parentRule, subRules, disambiguator, firstRules);
}
mapping XBNF::UntilToken::untilToken2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::UntilToken {
debug := self.debug;
terminal := self.terminal.map element2element(parentRule, subRules, disambiguator, firstRules);
}
mapping XBNF::Wildcard::wildcard2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::Wildcard {
debug := self.debug;
}
mapping XBNFwc::ZeroOrMore::zeroOrMore2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::RuleCall {
var oneRule : UntypedRule = self.map element2subRule(parentRule, subRules, disambiguator, firstRules);
subRules->add(oneRule);
var oneOrMoreRule : UntypedRule = oneRule.map rule2oneOrMoreSubRule(parentRule, subRules);
subRules->add(oneOrMoreRule);
var zeroOrMoreRule : UntypedRule = object UntypedRule {
element := object Disjunction {
debug := '0 or +';
conjunctions := Sequence {
object Conjunction {
elements := Sequence {
object XBNF::Epsilon {}
};
},
object Conjunction {
elements := Sequence {
object XBNF::RuleCall {
debug := oneOrMoreRule.name;
referredRule := oneOrMoreRule;
}
};
}
};
};
name := parentRule + '_' + subRules->size().toString();
};
subRules->add(zeroOrMoreRule);
debug := zeroOrMoreRule.name;
referredRule := zeroOrMoreRule
}
mapping XBNFwc::ZeroOrOne::zeroOrOne2element(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::RuleCall {
var me : CompoundElement = self;
var alternatives : Sequence(AbstractElement) = self.elements;
var zeroOrOneRule : UntypedRule = object UntypedRule {
element := object Disjunction {
debug := '0 or 1';
conjunctions := alternatives->iterate(e; acc : Sequence(Conjunction) = Sequence {
object Conjunction {
elements := Sequence {
object XBNF::Epsilon {}
};
}
} |
acc->append(object Conjunction {
elements := e.succession(Sequence{}, e)->map element2element(parentRule, subRules, e, firstRules);
}));
};
name := parentRule + '_' + subRules->size().toString();
};
subRules->add(zeroOrOneRule);
debug := zeroOrOneRule.name;
referredRule := zeroOrOneRule
}
-- Helpers
mapping XBNFwc::CompoundElement::element2subRule(parentRule : String, subRules : List(XBNF::UntypedRule), disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::UntypedRule {
var me : CompoundElement = self;
var alternatives : Sequence(AbstractElement) = self.elements;
element := object Disjunction {
debug := '1';
conjunctions := alternatives->iterate(e; acc : Sequence(Conjunction) = Sequence{} |
acc->append(object Conjunction {
elements := e.succession(Sequence{}, e)->map element2element(parentRule, subRules, e, firstRules);
}));
};
name := parentRule + '_' + subRules->size().toString();
}
mapping XBNF::AbstractRule::rule2oneOrMoreSubRule(parentRule : String, subRules : List(XBNF::UntypedRule)) : XBNF::UntypedRule {
name := parentRule + '_' + subRules->size().toString();
element := object Disjunction {
debug := '1 or +';
conjunctions := Sequence {
object Conjunction {
elements := Sequence {
object RuleCall {
debug := self.name;
referredRule := self;
}
};
},
object Conjunction {
elements := Sequence {
object XBNF::RuleCall {
debug := result.name;
referredRule := result;
},
object XBNF::RuleCall {
debug := self.name;
referredRule := self;
}
};
}
};
};
}
---------------------------------------------------------------------------------------
-- Return an in-order sequence of flattened terms.
---------------------------------------------------------------------------------------
helper XBNF::AbstractElement::succession(head : Sequence(AbstractElement), disambiguator : OclAny) : Sequence(AbstractElement)
{
return head->append(self);
}
helper XBNFwc::Succession::succession(head : Sequence(AbstractElement), disambiguator : OclAny) : Sequence(AbstractElement)
{
return self.elements->iterate(e; acc : Sequence(AbstractElement) = head | e.succession(acc, disambiguator));
}