blob: ece67a93354e413b744fa48de0a1ee5d0640a580 [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2012 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.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 EBNF Grammar to BNF:
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 normalize 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) };
var untypedRules : Sequence(UntypedRule) := grammars.allSubobjectsOfKind(UntypedRule)->selectByKind(UntypedRule);
untypedRules->forEach(untypedRule) {
untypedRule.name := untypedRule.typedRule.name + '_' + untypedRule.typedRule.subrules->indexOf(untypedRule).toString();
};
}
---------------------------------------------------------------------------------------
-- Copy the lexer rules
---------------------------------------------------------------------------------------
mapping XBNF::Syntax::grammars2lexerGrammar(firstRules : Set(TypedRule)) : XBNF::LexerGrammar {
name := self.name;
rules := self.grammars.rules->selectByKind(TerminalRule)->map terminalRule2rule(firstRules);
goals := self.grammars.goals.resolveone(TypedRule);
}
mapping XBNF::TerminalRule::terminalRule2rule(firstRules : Set(TypedRule)) : XBNF::TerminalRule
{
var subRules : List(XBNF::UntypedRule) = List{};
name := self.name;
type := self.type;
var candidate := self.element.map element2element(subRules, null, self, firstRules);
element := if candidate.oclIsKindOf(Disjunction)
then candidate
else if candidate.oclIsKindOf(Conjunction)
then object Disjunction {
debug := self.debug;
conjunctions += candidate.oclAsType(Conjunction);
}
else object Disjunction {
debug := self.debug;
conjunctions += object Conjunction {
debug := self.debug;
elements += candidate;
};
}
endif
endif;
debug := subRules->size().toString();
subrules := subRules->iterate(r; acc : Sequence(XBNF::UntypedRule) = Sequence{} | acc->append(r));
}
---------------------------------------------------------------------------------------
-- 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->selectByKind(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)));
goals := self.grammars->selectByKind(ParserGrammar).goals->first().resolveone(TypedRule);
}
mapping XBNF::ParserRule::parserRule2rule(firstRules : Set(TypedRule)) : XBNF::ParserRule
{
var subRules : List(XBNF::UntypedRule) = List{};
var theElement : AbstractElement = self.element.map element2element(subRules, null, self, firstRules);
var disjunction : Disjunction = theElement.asDisjunction();
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(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, 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(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
result := object Wildcard {
debug := 'default';
}.appendAsConjunctions(tailElement);
}
}
mapping XBNF::ActionAssignment::actionAssignment2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
result := object ActionAssignment {
debug := self.debug;
feature := self.feature;
operator := self.operator;
type := self.type;
}.appendAsConjunctions(tailElement);
}
}
mapping XBNFwc::Alternatives::alternativesAtRoot2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement
when { self.parentRule <> null }
{
init {
result := object Disjunction {
debug := self.debug;
conjunctions := self.elements->iterate(e; acc : Sequence(Conjunction) = Sequence {} |
let eFlat = e.flattenAndMap(subRules, null, firstRules) in
acc->append(eFlat.asConjunction()));
}.appendAsConjunctions(tailElement);
}
}
mapping XBNFwc::Alternatives::alternativesNested2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement
{
init {
var me : Alternatives = self;
var alternatives : OrderedSet(AbstractElement) = self.elements;
var oneRule : XBNF::UntypedRule = object Disjunction {
debug := '1 : ' + alternatives->size().toString();
conjunctions := alternatives->iterate(e; acc : Sequence(Conjunction) = Sequence{} |
let eFlat = e.flattenAndMap(subRules, null, firstRules) in
acc->append(eFlat.asConjunction()));
}.asRule();
subRules->add(oneRule);
result := oneRule.asRuleCall().appendAsConjunctions(tailElement);
}
}
mapping XBNF::CharacterRange::characterRange2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
result := object CharacterRange {
debug := self.debug;
left := self.left;
right := self.right;
}.appendAsConjunctions(tailElement);
}
}
mapping XBNF::Keyword::keyword2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
result := object Keyword {
debug := self.debug;
value := self.value;
}.appendAsConjunctions(tailElement);
}
}
mapping XBNF::KeywordAssignment::keywordAssignment2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
result := object KeywordAssignment {
debug := self.debug;
feature := self.feature;
operator := self.operator;
value := self.value;
}.appendAsConjunctions(tailElement);
}
}
mapping XBNF::NegatedToken::negatedToken2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
result := object NegatedToken {
debug := self.debug;
terminal := self.terminal.map element2element(subRules, null, disambiguator, firstRules);
}.appendAsConjunctions(tailElement);
}
}
//
// x+ Y
//
// X1: x
// X2: X1 Y
// X3: X1 X2
// X: X2 | X3
// - we must handle Y to avoid shift reduce conflicts
//
mapping XBNFwc::OneOrMore::oneOrMore2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
var eFlat := self.element.flattenAndMap(subRules, null, firstRules);
var oneRule : XBNF::UntypedRule = eFlat.asRule();
subRules->add(oneRule);
var oneOrMoreRule := object UntypedRule {};
oneOrMoreRule.element := object Disjunction { debug := '1 or +';
conjunctions := Sequence {
object Conjunction {
elements := Sequence { oneRule.asRuleCall() };
if (tailElement <> null) {
elements += tailElement;
};
},
object Conjunction {
elements := Sequence { oneRule.asRuleCall(), oneOrMoreRule.asRuleCall() };
}
};
};
subRules->add(oneOrMoreRule);
result := oneOrMoreRule.asRuleCall();
}
}
mapping XBNF::RuleCall::ruleCall2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
result := object RuleCall {
debug := self.debug;
referredRule := firstRules->select(r | r.name = self.referredRule.name)->any(true).late resolveone(XBNF::AbstractRule);
}.appendAsConjunctions(tailElement);
}
}
mapping XBNF::RuleCallAssignment::ruleCallAssignment2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
result := object RuleCallAssignment {
debug := self.debug;
feature := self.feature;
operator := self.operator;
referredRule := firstRules->select(r | r.name = self.referredRule.name)->any(true).late resolveone(XBNF::AbstractRule);
}.appendAsConjunctions(tailElement);
}
}
mapping XBNFwc::Succession::succession2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
var mappedTailElement : AbstractElement := if tailElement <> null then tailElement.map element2element(subRules, null, disambiguator, firstRules) else null endif;
var element : AbstractElement := self.flattenAndMap(subRules, mappedTailElement, firstRules);
result := element.asConjunction();
}
}
mapping XBNF::UntilToken::untilToken2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
result := object UntilToken {
debug := self.debug;
terminal := self.terminal.map element2element(subRules, null, disambiguator, firstRules);
}.appendAsConjunctions(tailElement);
}
}
mapping XBNF::Wildcard::wildcard2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
result := object Wildcard {
debug := self.debug;
}.appendAsConjunctions(tailElement);
}
}
//
// x* Y
//
// X1: x
// X2: Y
// X3: X1 X2
// X: X2 | X3
//
mapping XBNFwc::ZeroOrMore::zeroOrMore2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
var eFlat := self.element.flattenAndMap(subRules, null, firstRules);
var oneRule = eFlat.asRule();
subRules->add(oneRule);
var oneOrMoreRule := object UntypedRule {};
oneOrMoreRule.element := object Disjunction { debug := '1 or +';
conjunctions := Sequence {
object Conjunction {
elements := Sequence { oneRule.asRuleCall() };
},
object Conjunction {
elements := Sequence { oneOrMoreRule.asRuleCall(), oneRule.asRuleCall() };
}
};
};
subRules->add(oneOrMoreRule);
var zeroOrMoreRule = object Disjunction { debug := '0 or +';
conjunctions := Sequence {
object XBNF::Epsilon {}.asConjunction(),
oneOrMoreRule.asRuleCall().asConjunction()
};
}.asRule();
subRules->add(zeroOrMoreRule);
result := zeroOrMoreRule.asRuleCall().appendAsConjunctions(tailElement);
}
}
//
// x?
//
// X1: x
// X: epsilon | X1
//
mapping XBNFwc::ZeroOrOne::zeroOrOne2element(inout subRules : List(XBNF::UntypedRule), tailElement : AbstractElement, disambiguator : OclAny, firstRules : Set(TypedRule)) : XBNF::AbstractElement {
init {
var eFlat := self.element.flattenAndMap(subRules, null, firstRules);
var zeroOrOneRule : UntypedRule = object Disjunction {
debug := '0 or 1';
conjunctions := Sequence { object XBNF::Epsilon {}.asConjunction(), eFlat.asConjunction() };
}.asRule();
subRules->add(zeroOrOneRule);
result := zeroOrOneRule.asRuleCall().appendAsConjunctions(tailElement);
}
}
-- Helpers
---------------------------------------------------------------------------------------
-- Return the conjunction of this element and tailElement which may be null.
---------------------------------------------------------------------------------------
helper XBNF::AbstractElement::appendAsConjunctions(tailElement : AbstractElement) : AbstractElement {
return if tailElement = null then
self
else if tailElement.oclIsKindOf(Conjunction) then
object Conjunction { elements := tailElement.oclAsType(Conjunction).elements->prepend(self); }
else
object Conjunction { elements := Sequence{self, tailElement}; }
endif
endif;
}
helper XBNF::Conjunction::appendAsConjunctions(tailElement : AbstractElement) : AbstractElement {
return if tailElement = null then
self
else if tailElement.oclIsKindOf(Conjunction) then
object Conjunction { elements := tailElement.oclAsType(Conjunction).elements
->iterate(e; acc : Sequence(AbstractElement) = self.elements->asSequence() | acc->append(e));}
else
object Conjunction { elements := self.elements->append(tailElement);}
endif
endif;
}
---------------------------------------------------------------------------------------
-- Return a conjunction containing thos element.
---------------------------------------------------------------------------------------
helper AbstractElement::asConjunction() : Conjunction {
return object Conjunction { debug := '1'; elements := self->asSequence(); };
}
helper Conjunction::asConjunction() : Conjunction {
return self;
}
---------------------------------------------------------------------------------------
-- Return a disjunction containing thos element.
---------------------------------------------------------------------------------------
helper AbstractElement::asDisjunction() : Disjunction {
return object Disjunction { debug := '1'; conjunctions := self.asConjunction()->asSequence(); };
}
helper Disjunction::asDisjunction() : Disjunction {
return self;
}
---------------------------------------------------------------------------------------
-- Return a rule containing thos element.
---------------------------------------------------------------------------------------
helper AbstractElement::asRule() : UntypedRule {
return object UntypedRule {
element := self.asDisjunction();
};
}
helper AbstractRule::asRuleCall() : RuleCall {
return object RuleCall {
debug := self.name;
referredRule := self;
};
}
---------------------------------------------------------------------------------------
-- Return an in-order sequence of the flattened terms comprising head followed by self.
---------------------------------------------------------------------------------------
helper AbstractElement::flattenAndMap(inout subRules : List(XBNF::UntypedRule), outerTailElement : AbstractElement, firstRules : Set(TypedRule)) : AbstractElement {
var flatElements : Sequence(AbstractElement) := self.flatten(Sequence{}, self);
var flatSize : Integer = flatElements->size();
return Sequence{1..flatSize}->iterate(i; innerTailElement : AbstractElement = outerTailElement |
let iReverse = flatSize-i+1 in
let flatElement = flatElements->at(iReverse) in
flatElement.map element2element(subRules, innerTailElement, self, firstRules));
}
helper XBNF::AbstractElement::flatten(head : Sequence(AbstractElement), disambiguator : OclAny) : Sequence(AbstractElement)
{
return head->append(self);
}
helper XBNFwc::Succession::flatten(head : Sequence(AbstractElement), disambiguator : OclAny) : Sequence(AbstractElement)
{
return self.elements->iterate(e; acc : Sequence(AbstractElement) = head | e.flatten(acc, disambiguator));
}