blob: d150cb1ed75db8d04a0c7d062961334dff768a92 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014 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
*******************************************************************************/
package org.eclipse.ocl.examples.xtext2lpg
import org.eclipse.ocl.examples.xtext2lpg.XBNF.AbstractElement
import org.eclipse.ocl.examples.xtext2lpg.XBNF.AbstractRule
import org.eclipse.ocl.examples.xtext2lpg.XBNF.ActionAssignment
import org.eclipse.ocl.examples.xtext2lpg.XBNF.Disjunction
import org.eclipse.ocl.examples.xtext2lpg.XBNF.Epsilon
import org.eclipse.ocl.examples.xtext2lpg.XBNF.Keyword
import org.eclipse.ocl.examples.xtext2lpg.XBNF.KeywordAssignment
import org.eclipse.ocl.examples.xtext2lpg.XBNF.LexerGrammar
import org.eclipse.ocl.examples.xtext2lpg.XBNF.ParserGrammar
import org.eclipse.ocl.examples.xtext2lpg.XBNF.RuleCall
import org.eclipse.ocl.examples.xtext2lpg.XBNF.RuleCallAssignment
import org.eclipse.ocl.examples.xtext2lpg.XBNF.Syntax
import org.eclipse.ocl.examples.xtext2lpg.XBNF.TypedRule
import org.eclipse.ocl.examples.xtext2lpg.XBNF.CharacterRange
import org.eclipse.ocl.examples.xtext2lpg.XBNF.Wildcard
import org.eclipse.ocl.examples.xtext2lpg.XBNF.UntilToken
class GenerateLPGXtend extends GenerateLPGUtils
{
/*@NonNull*/ protected override String generateLPGKWLexer(/*@NonNull*/ Syntax syntax) {
return generateKWLexer(getLexerGrammar(syntax), getParserGrammar(syntax))
}
/*@NonNull*/ protected override String generateLPGLexer(/*@NonNull*/ Syntax syntax) {
return generateLexer(getLexerGrammar(syntax), getParserGrammar(syntax));
}
/*@NonNull*/ protected override String generateLPGParser(/*@NonNull*/ Syntax syntax) {
return generateParser(getParserGrammar(syntax));
}
protected def String generateKWLexer(/*@NonNull*/ LexerGrammar lexerGrammar, /*@NonNull*/ ParserGrammar parserGrammar) {
var keywordValues = getSortedKWValues(parserGrammar);
'''
%options slr
%options fp=«syntaxName»KWLexer,prefix=Char_
%options noserialize
%options package=«emitSyntaxPackage(lexerGrammar.syntax)»
%options template=../lpg/KeywordTemplateF.gi
%options export_terminals=("«syntaxName»Parsersym.java", "TK_")
%options include_directory="../lpg"
%Import
KWLexerMapF.gi
%End
%Define
--
-- Definition of macros used in the template
--
$action_class /.$file_prefix./
$eof_char /.Char_EOF./
$copyright_contributions /.*./
%End
%Notice
/./**
* «syntaxName» Keyword Lexer
* <copyright>
*******************************************************************************/
./
%End
%Globals
/../
%End
%Export
«FOR keywordValue : keywordValues»
«emitLabel(keywordValue)»
«ENDFOR»
%End
%Start
KeyWord
%End
%Rules
-- The Goal for the parser is a single Keyword
KeyWord ::=
«FOR keywordValue : keywordValues SEPARATOR '\n\n| '»«FOR c : keywordValue.toCharArray() SEPARATOR ' '»«c»«ENDFOR»
/.$BeginAction
$setResult($_«emitLabel(keywordValue)»);
$EndAction
./«ENDFOR»
%End
'''
}
protected def String generateLexer(/*@NonNull*/ LexerGrammar lexerGrammar, /*@NonNull*/ ParserGrammar parserGrammar) {
var syntax = lexerGrammar.getSyntax();
var syntaxName = emitSyntaxName(syntax);
var punctValues = getSortedPunctValues(parserGrammar);
var terminalRules = getSortedTerminalRules(syntax);
var punctChars = getSortedPunctChars(lexerGrammar);
var characterRanges = getSortedCharacterRanges(lexerGrammar);
'''
%options escape=$
%options la=2
%options fp=«syntaxName»Lexer,prefix=Char_
%options single-productions
%options noserialize
%options package=«emitSyntaxPackage(syntax)»
%options template=../lpg/LexerTemplateF.gi
%options filter=«syntaxName»KWLexer.gi
%options export_terminals=("«syntaxName»Parsersym.java", "TK_")
%options include_directory="../lpg"
%Define
--
-- Definition of macro used in the included file LexerBasicMap.g
-- We redefine that one defined by EssentialOCLLexer
--
$kw_lexer_class /.«syntaxName»KWLexer./
%End
%Export
«FOR terminalRule : terminalRules»
«terminalRule.name»
«ENDFOR»
«FOR keywordValue : punctValues»
«emitLabel(keywordValue)»
«ENDFOR»
%End
%Terminals
«FOR characterRange : characterRanges»
«FOR c : getCharacters(characterRange) SEPARATOR ' '»«c»«ENDFOR»
«ENDFOR»
«FOR c : punctChars»
«emitLabel(c)» ::= «emitQuotedCharacter(c)»
«ENDFOR»
%End
%Start
Token
%End
%Rules
«FOR keywordValue : punctValues»
Token ::= «FOR c : keywordValue.toCharArray() SEPARATOR ' '»'«c»'«ENDFOR»
/.$BeginAction
makeToken($_«emitLabel(keywordValue)»);
$EndAction
./
«ENDFOR»
«FOR characterRange : characterRanges»
«characterRange.getDebug()» -> «FOR c : getCharacters(characterRange) SEPARATOR ' | '»'«c»'«ENDFOR»
«ENDFOR»
«FOR terminalRule : terminalRules»
«generateTerminalRule(terminalRule)»
«ENDFOR»
%End
'''
}
protected def String generateParser(/*@NonNull*/ ParserGrammar parserGrammar) {
var syntax = parserGrammar.getSyntax();
var syntaxName = emitSyntaxName(syntax);
'''
%options escape=$
%options la=1
%options fp=«syntaxName»Parser,prefix=TK_
%options noserialize
%options package=«emitSyntaxPackage(syntax)»
%options import_terminals=«syntaxName»Lexer.gi
%options ast_type=CSTNode
%options template=dtParserTemplateF.gi
%options include_directory=".;../lpg"
%Start
«FOR rule : parserGrammar.goals»
«rule.name»
«ENDFOR»
%End
%Notice
/./**
*******************************************************************************/
./
%End
%Globals
/.
/* imports */
./
%End
--%KeyWords
-- Reserved keywords
-- body context def derive endpackage init inv package post pre static
-- Restricted keywords
-- OclMessage
--%End
%Terminals
«FOR terminalRule : getSortedTerminalRules(syntax)»
«terminalRule.name»
«ENDFOR»
«FOR keywordValue : getSortedPunctValues(parserGrammar)»
«emitLabel(keywordValue)» ::= '«keywordValue»'
«ENDFOR»
%End
%Rules
«FOR parserRule : getSortedParserRules(parserGrammar) SEPARATOR '\n
«FOR rule : selectRules(parserGrammar.rules, parserRule.name)»
«generateParserRule(rule)»
«ENDFOR»
«ENDFOR»
%End
'''
}
protected def String generateParserRule(TypedRule rule) {
'''
«generateParserDisjunction(rule)»
«FOR subrule : getSortedSubRules(rule.subrules)»
«generateParserDisjunction(subrule)»
«ENDFOR»
'''
}
protected def String generateTerminalRule(TypedRule rule) {
'''
«generateLexerDisjunction(rule)»
«FOR subrule : getSortedSubRules(rule.subrules)»
«generateLexerDisjunction(subrule)»
«ENDFOR»
'''
}
protected def String generateLexerDisjunction(AbstractRule rule) {
'''
«FOR conjunction : getSortedConjunctions(rule.element as Disjunction)»
«rule.name» ::=«IF conjunction.elements.isEmpty()» %empty«ELSE»«FOR element : conjunction.elements» «generateTerm(element)»«ENDFOR»«ENDIF»
/.$BeginAction
makeToken($_«rule.name»);
$EndAction
./
«ENDFOR»
'''
}
protected def String generateParserDisjunction(AbstractRule rule) {
'''
«FOR conjunction : getSortedConjunctions(rule.element as Disjunction)»
«rule.name» ::=«IF conjunction.elements.isEmpty()» %empty«ELSE»«FOR element : conjunction.elements» «generateTerm(element)»«ENDFOR»«ENDIF» --«nextState()»
«ENDFOR»
'''
}
protected def String generateTerm(AbstractElement element) {
switch element {
ActionAssignment: return ""
CharacterRange: return element.getDebug()
Epsilon: return "%empty"
RuleCallAssignment: return element.referredRule.name
RuleCall: return element.referredRule.name
KeywordAssignment: return emitLabel(element.value)
Keyword: return emitLabel(element.value)
UntilToken: return "UNTIL " + generateTerm(element.terminal)
Wildcard: return '.'
default: return "<<<" + element.eClass.name + ">>>"
}
}
}