/*
* ******************************************************************************
* MontiCore Language Workbench
* Copyright (c) 2015, MontiCore, All rights reserved.
*
* This project is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this project. If not, see <http://www.gnu.org/licenses/>.
* ******************************************************************************
*/
package de.monticore.codegen.parser.antlr;
import static de.monticore.codegen.parser.ParserGeneratorHelper.printIteration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import de.monticore.ast.ASTNode;
import de.monticore.codegen.mc2cd.MCGrammarSymbolTableHelper;
import de.monticore.codegen.parser.ParserGeneratorHelper;
import de.monticore.grammar.DirectLeftRecursionDetector;
import de.monticore.grammar.MCGrammarInfo;
import de.monticore.grammar.HelperGrammar;
import de.monticore.grammar.PredicatePair;
import de.monticore.grammar.grammar._ast.ASTAlt;
import de.monticore.grammar.grammar._ast.ASTAnything;
import de.monticore.grammar.grammar._ast.ASTBlock;
import de.monticore.grammar.grammar._ast.ASTClassProd;
import de.monticore.grammar.grammar._ast.ASTConstant;
import de.monticore.grammar.grammar._ast.ASTConstantGroup;
import de.monticore.grammar.grammar._ast.ASTEnumProd;
import de.monticore.grammar.grammar._ast.ASTEof;
import de.monticore.grammar.grammar._ast.ASTLexActionOrPredicate;
import de.monticore.grammar.grammar._ast.ASTLexAlt;
import de.monticore.grammar.grammar._ast.ASTLexAnyChar;
import de.monticore.grammar.grammar._ast.ASTLexBlock;
import de.monticore.grammar.grammar._ast.ASTLexChar;
import de.monticore.grammar.grammar._ast.ASTLexCharRange;
import de.monticore.grammar.grammar._ast.ASTLexNonTerminal;
import de.monticore.grammar.grammar._ast.ASTLexOption;
import de.monticore.grammar.grammar._ast.ASTLexProd;
import de.monticore.grammar.grammar._ast.ASTLexSimpleIteration;
import de.monticore.grammar.grammar._ast.ASTLexString;
import de.monticore.grammar.grammar._ast.ASTMCAnything;
import de.monticore.grammar.grammar._ast.ASTNonTerminal;
import de.monticore.grammar.grammar._ast.ASTOptionValue;
import de.monticore.grammar.grammar._ast.ASTProd;
import de.monticore.grammar.grammar._ast.ASTSemanticpredicateOrAction;
import de.monticore.grammar.grammar._ast.ASTTerminal;
import de.monticore.grammar.grammar._ast.GrammarNodeFactory;
import de.monticore.grammar.grammar_withconcepts._ast.ASTAction;
import de.monticore.grammar.grammar_withconcepts._visitor.Grammar_WithConceptsVisitor;
import de.monticore.grammar.symboltable.MCGrammarSymbol;
import de.monticore.grammar.symboltable.MCProdComponentSymbol;
import de.monticore.grammar.symboltable.MCProdSymbol;
import de.monticore.symboltable.Symbol;
import de.se_rwth.commons.logging.Log;
/**
* TODO: Write me!
*
* @author (last commit) $Author$
* @version $Revision$, $Date$
*/
public class Grammar2Antlr implements Grammar_WithConceptsVisitor {
private MCGrammarSymbol grammarEntry;
/**
* This list is used for the detection of the left recursion
*/
private ArrayList<ASTAlt> altList = new ArrayList<>();
private DirectLeftRecursionDetector leftRecursionDetector = new DirectLeftRecursionDetector();
private SourcePositionActions positionActions;
private AttributeCardinalityConstraint attributeConstraints;
private ASTConstructionActions astActions;
private List<String> productionAntlrCode = Lists.newArrayList();
private StringBuilder codeSection;
private StringBuilder action;
private MCGrammarInfo grammarInfo;
private ParserGeneratorHelper parserHelper;
public Grammar2Antlr(
ParserGeneratorHelper parserGeneratorHelper,
MCGrammarInfo grammarInfo) {
Preconditions.checkArgument(parserGeneratorHelper.getGrammarSymbol() != null);
this.grammarEntry = parserGeneratorHelper.getGrammarSymbol();
this.grammarInfo = grammarInfo;
this.parserHelper = parserGeneratorHelper;
astActions = new ASTConstructionActions(parserGeneratorHelper);
attributeConstraints = new AttributeCardinalityConstraint(parserGeneratorHelper);
positionActions = new SourcePositionActions(parserGeneratorHelper);
}
/**
* Prints Lexer rule
*
* @param ast - lexer production
*/
@Override
public void handle(ASTLexProd ast) {
startCodeSection("ASTLexProd " + ast.getName());
if (ast.isFragment()) {
addToCodeSection("fragment ");
}
addToCodeSection(ast.getName(), " ");
endCodeSection();
// Print option
if (ast.getLexOption().isPresent()) {
ast.getLexOption().get().accept(getRealThis());
}
startCodeSection();
addToCodeSection("\n:");
// Add init action
if (ast.getInitAction().isPresent()) {
addToCodeSection("{", ParserGeneratorHelper.getText(ast.getInitAction().get()), "\n}");
}
endCodeSection();
createAntlrCodeForLexAlts(ast.getAlts());
// Add Action
startCodeSection();
if (ast.getEndAction().isPresent()) {
if (ast.getEndAction().isPresent()) {
addToCodeSection("{", ParserGeneratorHelper.getText(ast.getEndAction().get()), "\n}");
}
}
addToCodeSection(";");
endCodeSection(ast);
}
/**
* Prints Parser rule
*
* @param ast parser production
*/
@Override
public void handle(ASTClassProd ast) {
startCodeSection("ASTClassProd " + ast.getName());
// Create eof and dummy rules
String ruleName = HelperGrammar.getRuleNameForAntlr(ast);
Optional<MCProdSymbol> ruleByName = grammarEntry
.getProdWithInherited(HelperGrammar.getRuleName(ast));
// String classnameFromRulenameorInterfacename = ruleByName.getType()
// .getQualifiedName();
String classnameFromRulenameorInterfacename = MCGrammarSymbolTableHelper
.getQualifiedName(ruleByName.get());
// Head of Rule
// Pattern:
// String tmp =
// "%name% returns [%uname% ret = %defaultvalue%] %options% ";
// TODO: Antlr4 Dies war die Alternative, wenn es keine Parameter
// gibt.
// Ist aber wahrscheinlich so korrekt,
// erzeugt bestimmt Default für ret ...
addDummyRules(HelperGrammar.getRuleName(ast), ruleName,
classnameFromRulenameorInterfacename);
String options = "";
List<ASTAlt> alts = parserHelper.getAlternatives(ast);
// Antlr4: new syntax
if (alts.isEmpty()) {
options = "@rulecatch{}";
}
// Start code codeSection for rules
addToCodeSection(ruleName, " returns [", classnameFromRulenameorInterfacename, " ret = ",
MCGrammarSymbolTableHelper.getDefaultValue(ruleByName.get()), "]\n", options);
startAction();
// Add actions
if (ast.getAction().isPresent() && ast.getAction().get() instanceof ASTAction) {
addToAction(ParserGeneratorHelper.getText(ast.getAction().get()));
}
// Action at beginning of rule @init
addToAction(astActions.getActionForRuleBeforeRuleBody(ast));
// Action for determining positions
addToAction(positionActions.startPosition(ast));
// Action for determining positions of comments (First set position)
addToAction("setActiveASTNode(_aNode);\n");
addToAction(attributeConstraints.addActionForRuleBeforeRuleBody(ast));
if (!isActionEmpty()) {
addToCodeSection("@init");
endAction();
}
// Action at end of rule
startAction();
addToAction(positionActions.endPosition(ast));
addToAction(attributeConstraints.addActionForRuleAfterRuleBody(ast));
if (!isActionEmpty()) {
addToCodeSection("\n@after");
endAction();
}
endCodeSection();
// End code codeSection for rules
startCodeSection();
addToCodeSection("\n : ");
List<PredicatePair> subRules = grammarInfo
.getSubRulesForParsing(HelperGrammar.getRuleName(ast));
if (subRules != null && !subRules.isEmpty()) {
addToCodeSection("// Adding subrules");
endCodeSection();
int i = 0;
for (PredicatePair x : subRules) {
if (x.getComponent().isPresent()) {
x.getComponent().get().accept(getRealThis());
}
startCodeSection();
String subRuleVar = "subRuleVar" + i;
addToCodeSection("(" + subRuleVar + " = "
+ HelperGrammar.getRuleNameForAntlr(x.getClassname())
+ "{$ret = $" + subRuleVar + ".ret;}) | ");
addToCodeSection("\n// end subrules");
endCodeSection();
}
}
else {
endCodeSection();
}
// Iterate over all Components
createAntlrCodeForAlts(alts);
addToAntlrCode(";");
endCodeSection(ast);
}
@Override
public void handle(ASTEnumProd ast) {
// Check if user excluded this rule from the code generation
startCodeSection("ASTEnumProd " + ast.getName());
// Create eof and dummy rules
String ruleName = HelperGrammar.getRuleNameForAntlr(ast.getName());
Optional<MCProdSymbol> ruleByName = grammarEntry.getProdWithInherited(ast
.getName());
// Head of Rule
addToCodeSection(ruleName + " returns ["
+ MCGrammarSymbolTableHelper.getQualifiedName(ruleByName.get()) + " ret = "
+ MCGrammarSymbolTableHelper.getDefaultValue(ruleByName.get()) + "] ");
addToCodeSection("\n: ");
String sep = "";
for (ASTConstant c : ast.getConstants()) {
addToCodeSection(sep);
if (grammarInfo.isKeyword(c.getName(), grammarEntry)) {
addToCodeSection("\n'" + c.getName() + "'");
}
else {
addToCodeSection("\n", parserHelper.getLexSymbolName(c.getName()));
}
String temp1 = "";
temp1 += "$ret = " + MCGrammarSymbolTableHelper.getQualifiedName(ruleByName.get())
+ "."
+ parserHelper.getConstantNameForConstant(c) + ";";
if (!temp1.isEmpty()) {
addToCodeSection("\n{" + temp1 + "}");
}
sep = "|";
}
addToCodeSection(";\n");
endCodeSection(ast);
}
/**
* Handles a ConstantGroup (something in [] )
*
* @param ast
*/
@Override
public void handle(ASTConstantGroup ast) {
startCodeSection(ast);
boolean iterated = false;
if (ast.getSymbol().isPresent() && ast.getSymbol().get() instanceof MCProdComponentSymbol) {
iterated = MCGrammarSymbolTableHelper
.isConstGroupIterated((MCProdComponentSymbol) ast.getSymbol().get());
}
// One entry leads to boolean isMethods
if (!iterated) {
ASTConstant x = ast.getConstants().get(0);
if (!grammarInfo.isKeyword(x.getName(), grammarEntry)) {
addToCodeSection(parserHelper.getLexSymbolName(x.getName()));
}
else {
addToCodeSection("'" + x.getName() + "'");
}
startAction();
addToAction(astActions.getConstantInConstantGroupSingleEntry(x, ast));
endActionNewLine();
}
// More than one entry leads to an int
else {
addToCodeSection("(");
String del = "";
for (Iterator<ASTConstant> iter = ast.getConstants().iterator(); iter
.hasNext();) {
addToCodeSection(del);
ASTConstant x = iter.next();
if (!grammarInfo.isKeyword(x.getName(), grammarEntry)) {
/* // Template //
* a.set%namegroup%(%astconstclassname%.%constantname%); tmp =
* "%name% {%actions%}";
*
* // Replace values tmp = tmp.replaceAll("%astconstclassname%",
* constClassName); tmp = tmp.replaceAll("%name%",
* grammarEntry.getLexSymbolName(x.getName())); tmp =
* tmp.replaceAll("%namegroup%",
* NameHelper.firstToUpper(a.getUsageName()));
*
* if (x.getHumanName() == null) { tmp =
* tmp.replaceAll("%constantname%",
* grammarEntry.getLexSymbolName(x.getName())); } else { tmp =
* tmp.replaceAll("%constantname%", (x.getHumanName().toUpperCase()));
* } */
addToCodeSection(parserHelper.getLexSymbolName(x.getName()));
}
else {
/* // Template //
* a.set%namegroup%(%astconstclassname%.%constantname%); tmp =
* "'%name%' {%actions%}";
*
* tmp = tmp.replaceAll("%astconstclassname%", constClassName); tmp =
* tmp.replaceAll("%name%", (x.getName())); tmp =
* tmp.replaceAll("%namegroup%",
* NameHelper.firstToUpper(a.getUsageName()));
*
* tmp = tmp.replaceAll("%constantname%",
* (x.getName().toUpperCase())); */
addToCodeSection("'" + x.getName() + "'");
}
startAction();
addToAction(astActions.getConstantInConstantGroupMultipleEntries(x, ast));
endActionNewLine();
del = "|\n";
}
addToCodeSection(")");
}
endCodeSection(ast);
}
/**
* Print alternatives
*
* @param ast
*/
public void createAntlrCodeForAlts(List<ASTAlt> ast) {
String del = "";
for (Iterator<ASTAlt> iter = ast.iterator(); iter.hasNext();) {
addToAntlrCode(del);
iter.next().accept(getRealThis());
del = "|";
}
}
public void createAntlrCodeForLexAlts(List<ASTLexAlt> ast) {
String del = "";
for (ASTLexAlt anAst : ast) {
addToAntlrCode(del);
anAst.accept(getRealThis());
del = "|";
}
}
@Override
public void handle(ASTLexBlock ast) {
startCodeSection();
if (ast.isNegate()) {
addToCodeSection("~");
}
// Start of Block
addToCodeSection("(");
if (ast.getOption().isPresent()) {
addToCodeSection("\noptions {", ast.getOption().get().getID(), "=", ast.getOption().get()
.getValue(), ";}");
}
if (ast.getInitAction().isPresent()) {
addToCodeSection("{", ParserGeneratorHelper.getText(ast.getInitAction().get()), "}");
}
endCodeSection();
// Visit all alternatives
createAntlrCodeForLexAlts(ast.getLexAlts());
// Start of Block with iteration
startCodeSection();
addToCodeSection(")\n", printIteration(ast.getIteration()));
endCodeSection();
}
@Override
public void handle(ASTLexSimpleIteration ast) {
startCodeSection();
// Start of Block
addToAntlrCode("(");
// Visit all alternatives
if (ast.getLexChar().isPresent()) {
ast.getLexChar().get().accept(getRealThis());
}
else if (ast.getLexString().isPresent()) {
ast.getLexString().get().accept(getRealThis());
}
else if (ast.getLexNonTerminal().isPresent()) {
ast.getLexNonTerminal().get().accept(getRealThis());
}
else if (ast.getLexAnyChar().isPresent()) {
ast.getLexAnyChar().get().accept(getRealThis());
}
// Close block and print iteration
addToCodeSection(")\n", printIteration(ast.getIteration()));
endCodeSection();
if (ast.isQuestion()) {
addToAntlrCode("?");
}
}
/**
* Print Block structure, 1:1 copy to Antlr Differences occurr, if it is a
* syntatic predicate, which uses the same syntax but ends with "=>" Turn
* extra code generation off in these block and use antlr syntax only
* (indicated by inpredicate)
*
* @param a Block to be printed
*/
@Override
public void handle(ASTBlock a) {
// Start of Block
startCodeSection();
addToCodeSection("(");
// Print options
if (a.getOption().isPresent()) {
addToCodeSection("\n options {");
for (ASTOptionValue x : a.getOption().get().getOptionValues()) {
addToCodeSection("\n " + x.getKey() + "=" + x.getValue() + ";");
}
addToCodeSection("\n }");
}
// Print init actions
if (a.getInitAction().isPresent()) {
addToCodeSection("{" + ParserGeneratorHelper.getText(a.getInitAction().get()) + "}");
}
endCodeSection();
// Visit all alternatives
createAntlrCodeForAlts(a.getAlts());
// Start of Block with iteration
startCodeSection();
addToCodeSection("\n)" + printIteration(a.getIteration()));
endCodeSection();
}
@Override
public void visit(ASTTerminal ast) {
startCodeSection("ASTTerminal " + ast.getName());
addToCodeSection("(");
String rulename;
if (grammarInfo.isKeyword(ast.getName(), grammarEntry)) {
rulename = "'" + ast.getName() + "'";
}
else {
rulename = parserHelper.getLexSymbolName(ast.getName().intern());
}
// No actions in predicates
// Template engine cannot be used for substition in rare cases
addToCodeSection(rulename); // + " %initaction% %actions% ) %iteration% ";
boolean iteratedItself = HelperGrammar.isIterated(ast);
boolean isAttribute = ast.getUsageName().isPresent();
boolean isList = iteratedItself;
Optional<? extends Symbol> ruleComponent = ast.getSymbol();
if (ruleComponent.isPresent() && ruleComponent.get() instanceof MCProdComponentSymbol) {
MCProdComponentSymbol componentSymbol = (MCProdComponentSymbol) ruleComponent.get();
isList = componentSymbol.isList();
}
// Add Actions
startAction();
if (isAttribute) {
if (isList) {
addToAction(astActions.getActionForTerminalIteratedAttribute(ast));
}
else {
addToAction(astActions.getActionForTerminalNotIteratedAttribute(ast));
}
}
else {
addToAction(astActions.getActionForTerminalIgnore(ast));
}
endAction();
addToCodeSection(")", printIteration(ast.getIteration()));
endCodeSection(ast);
}
@Override
public void visit(ASTLexCharRange ast) {
startCodeSection();
if (ast.isNegate()) {
addToCodeSection("~");
}
addToCodeSection("'", ast.getLowerChar(), "'..'", ast.getUpperChar(), "' ");
endCodeSection();
}
@Override
public void visit(ASTLexChar a) {
startCodeSection();
if (a.isNegate()) {
addToCodeSection("~");
}
addToCodeSection("'", a.getChar(), "' ");
endCodeSection();
}
@Override
public void visit(ASTLexAnyChar a) {
startCodeSection();
addToCodeSection(".");
endCodeSection();
}
@Override
public void visit(ASTLexString a) {
startCodeSection();
addToCodeSection("'");
addToCodeSection(a.getString(), "' ");
endCodeSection();
}
@Override
public void visit(ASTLexActionOrPredicate a) {
startCodeSection();
addToCodeSection("{");
addToCodeSection(ParserGeneratorHelper.getText(a.getExpressionPredicate()), "}");
if (a.isPredicate()) {
addToCodeSection("?");
}
endCodeSection();
}
@Override
public void visit(ASTLexNonTerminal ast) {
startCodeSection();
addToCodeSection(" ");
addToCodeSection(ast.getName(), " ");
endCodeSection();
}
@Override
public void visit(ASTLexOption ast) {
addToAntlrCode("options {" + ast.getID() + " = " + ast.getValue() + "; } ");
}
/**
* Print anything in {} which can be an Action or an semantic predicate for
* antlr, depending on a ? at the end of the block
*
* @param ast
*/
@Override
public void visit(ASTSemanticpredicateOrAction ast) {
startCodeSection();
addToCodeSection("{");
if (ast.getExpressionPredicate().isPresent()) {
addToCodeSection(ParserGeneratorHelper.getText(ast.getExpressionPredicate().get()), "}");
}
else if (ast.getAction().isPresent()) {
addToCodeSection(ParserGeneratorHelper.getText(ast.getAction().get()), "}");
}
else {
Log.error("0xA0327 neither expression predicate nor action is set.");
}
if (ast.isPredicate()) {
addToCodeSection("?");
}
endCodeSection();
}
/**
* Handles an non-terminal thats stated in a grammar
*
* @param ast
*/
@Override
public void visit(ASTNonTerminal ast) {
startCodeSection();
Optional<MCProdSymbol> prod = grammarEntry.getProdWithInherited(ast.getName());
if (!prod.isPresent()) {
Log.error("0xA2201 Production symbol for " + ast.getName() + "couldn't be resolved.",
ast.get_SourcePositionStart());
}
// Lexer Rule
if (prod.get().isLexerProd()) {
addCodeForLexerRule(ast);
}
// Other Rule called
else if (prod.get().isParserProd()
||
prod.get().isInterface()
||
prod.get().isAbstract()
||
prod.get().isEnum()) {
addCodeForRuleReference(ast);
}
// external rule called (first+second version)
else {
addToCodeSection(embedded(ast));
}
endCodeSection();
}
/**
* Print end-of-file token, which is simply an EOF
*
* @param a
*/
@Override
public void visit(ASTEof a) {
addToAntlrCode("EOF");
}
@Override
public void visit(ASTAnything a) {
addToAntlrCode(".");
}
@Override
public void visit(ASTMCAnything a) {
addToAntlrCode(ParserGeneratorHelper.MONTICOREANYTHING);
}
@Override
public void visit(ASTAlt alt) {
altList.add(alt);
if (alt.isRightAssoc()) {
addToAntlrCode(ParserGeneratorHelper.RIGHTASSOC);
}
}
@Override
public void endVisit(ASTAlt alt) {
if (!altList.isEmpty()) {
altList.remove(altList.size() - 1);
}
}
// ----------------- End of visit methods
// ---------------------------------------------
public List<String> createAntlrCode(ASTProd ast) {
clearAntlrCode();
parserHelper.resetTmpVarNames();
ast.accept(getRealThis());
return getAntlrCode();
}
/**
* Write extra Rules for Interfaces Example A implements C = zz ; B implements
* C = zz ; results in an extra rule C : A | B;
*/
public List<String> createAntlrCodeForInterface(MCProdSymbol interfaceRule) {
clearAntlrCode();
String interfacename = interfaceRule.getName();
// Dummy rules
String ruleName = HelperGrammar.getRuleNameForAntlr(interfacename);
String usageName = MCGrammarSymbolTableHelper.getQualifiedName(interfaceRule);
startCodeSection(interfaceRule.getName());
addDummyRules(interfacename, ruleName, usageName);
addToAntlrCode(HelperGrammar.getRuleNameForAntlr(interfacename) + " returns ["
+ usageName + " ret]: (");
String del = "";
int count = 0;
for (PredicatePair interf : grammarInfo.getSubRulesForParsing(interfacename)) {
addToAntlrCode(del);
if (interf.getComponent().isPresent()) {
interf.getComponent().get().accept(getRealThis());
}
startCodeSection();
addToCodeSection("tmp" + count + "="
+ HelperGrammar.getRuleNameForAntlr(interf.getClassname()));
// TODO GV: don't need it anymore?
// int size = 0;
// if (prod != null) {
// size = prod.getNoParam();
// }
//
// if (size > 0) {
// addToCodeSection("[null");
// for (int j = 1; j < size; j++) {
// addToCodeSection(",null");
// }
// addToCodeSection("]");
// }
// Action for AntLR4
addToCodeSection("\n{$ret=$tmp" + count + ".ret;}");
count++;
del = " | ";
endCodeSection();
}
addToAntlrCode(");");
return getAntlrCode();
}
public List<String> getHWParserJavaCode() {
return grammarInfo.getAdditionalParserJavaCode();
}
public List<String> getHWLexerJavaCode() {
return grammarInfo.getAdditionalLexerJavaCode();
}
// ----------------------------------------------------------------------------------------------
private void addCodeForLexerRule(ASTNonTerminal ast) {
startCodeSection();
addToCodeSection("(");
// AntLR2 -> AntLR4: Replace : by =
// tmp = "( %tmp%=%rulename% %initaction% %actions%";
addToCodeSection(parserHelper.getTmpVarName(ast), "=", ast.getName());
// Add Actions
startAction();
Optional<MCProdSymbol> scope = MCGrammarSymbolTableHelper.getEnclosingRule(ast);
if (scope.isPresent()) {
addToAction(attributeConstraints.addActionForNonTerminal(ast));
String attributename = HelperGrammar.getUsuageName(ast);
if (scope.isPresent() && scope.get().getProdComponent(attributename).isPresent()
&& scope.get().getProdComponent(attributename).get().isList()) {
addToAction(astActions.getActionForLexerRuleIteratedAttribute(ast));
}
else {
addToAction(astActions.getActionForLexerRuleNotIteratedAttribute(ast));
}
}
endAction();
addToCodeSection("\n");
endCodeSection();
if (ast.isPlusKeywords()) {
addToAntlrCode("/* Automatically added keywords " + grammarInfo.getKeywords()
+ " */");
// TODO PN, GV
for (String y : grammarInfo.getKeywords()) {
addToAntlrCode(" | ");
ASTTerminal term = GrammarNodeFactory.createASTTerminal();
ast.get_Children().add(term);
// term.set_Parent(ast);
term.setName(y);
term.setUsageName(HelperGrammar.getUsuageName(ast));
Optional<? extends Symbol> ruleComponent = ast.getSymbol();
if (ruleComponent.isPresent() && ruleComponent.get() instanceof MCProdComponentSymbol) {
MCProdComponentSymbol componentSymbol = (MCProdComponentSymbol)ruleComponent.get();
Optional<MCProdSymbol> rule = MCGrammarSymbolTableHelper
.getEnclosingRule(componentSymbol);
if (rule.isPresent()) {
addActionForKeyword(term, rule.get(), componentSymbol.isList());
}
}
}
}
addToAntlrCode(") " + printIteration(ast.getIteration()));
}
/**
* print code for references to embedded rules
*/
private String embedded(ASTNonTerminal ast) {
return "";
}
/**
* Print code for references to other rules in the same grammar
*
* @param ast
* @return
*/
private void addCodeForRuleReference(ASTNonTerminal ast) {
Optional<MCProdSymbol> scope = MCGrammarSymbolTableHelper.getEnclosingRule(ast);
boolean isLeftRecursive = false;
if (scope.isPresent() && scope.get().getName().equals(ast.getName())
&& !altList.isEmpty()) {
// Check if rule is left recursive
isLeftRecursive = leftRecursionDetector
.isAlternativeLeftRecursive(altList.get(0), ast);
}
startCodeSection();
// In star enviroment use add-method, else use set methods
// Do not build up ast in predicates
String iteration = printIteration(ast.getIteration());
String braceopen = iteration.isEmpty() ? "" : "(";
String braceclose = iteration.isEmpty() ? "" : ")";
String tmpVarName = parserHelper.getTmpVarName(ast);
addToCodeSection(braceopen, " ", tmpVarName, "=", HelperGrammar.getRuleNameForAntlr(ast));
startAction();
if (isLeftRecursive) {
addToAction(astActions
.getActionForInternalRuleNotIteratedLeftRecursiveAttribute(ast));
}
addToAction(attributeConstraints.addActionForNonTerminal(ast));
// TODO GV:
String attributename = HelperGrammar.getUsuageName(ast);
if (scope.isPresent() && scope.get().getProdComponent(attributename).isPresent()
&& scope.get().getProdComponent(attributename).get().isList()) {
addToAction(astActions.getActionForInternalRuleIteratedAttribute(ast));
}
else {
addToAction(astActions.getActionForInternalRuleNotIteratedAttribute(ast));
}
// TODO GV: replaceAll("..", ".")); is deprecated?
endAction();
addToCodeSection(braceclose, " ", iteration, " ");
endCodeSection();
}
private void addActionForKeyword(ASTTerminal keyword, MCProdSymbol rule, boolean isList) {
startCodeSection();
addToCodeSection("(");
String rulename = "";
if (grammarInfo.isKeyword(keyword.getName(), grammarEntry)) {
rulename = "'" + keyword.getName() + "'";
}
// No actions in predicates
// Template engine cannot be used for substition in rare cases
addToCodeSection(rulename); // + " %initaction% %actions% ) %iteration% ";
boolean isAttribute = (keyword.getUsageName().isPresent());
// Add Actions
startAction();
if (isAttribute) {
if (isList) {
addToAction(astActions.getActionForTerminalIteratedAttribute(keyword));
}
else {
addToAction(astActions.getActionForTerminalNotIteratedAttribute(keyword));
}
}
else {
addToAction(astActions.getActionForTerminalIgnore(keyword));
}
endAction();
addToCodeSection(")", printIteration(keyword.getIteration()));
endCodeSection();
}
private void addDummyRules(String rulenameInternal, String ruleName,
String usageName) {
addToCodeSection("\n\n", ruleName, "_eof returns [", usageName, " ret = null] :\n tmp = ",
ruleName, " {$ret = $tmp.ret;} ");
String follow = "EOF";
String end = " ;\n\n";
Optional<ASTAlt> follow2 = parserHelper.getAlternativeForFollowOption(rulenameInternal);
if (!follow2.isPresent()) {
addToCodeSection(follow, end);
endCodeSection();
return;
}
endCodeSection();
follow2.get().accept(getRealThis());
addToAntlrCode(end);
}
// ----------------------------------------------------------
/**
* Gets the antlr code (for printing)
*
* @return
*/
private List<String> getAntlrCode() {
return ImmutableList.copyOf(productionAntlrCode);
}
/**
* Adds the given code to antlr code
*
* @param code
*/
private void addToAntlrCode(String code) {
productionAntlrCode.add(code);
}
/**
* Clears antlr code
*/
private void clearAntlrCode() {
productionAntlrCode.clear();
}
/**
* Adds the given code to antlr code
*
* @param code
*/
private void addToAntlrCode(StringBuilder code) {
addToAntlrCode(code.toString());
}
/**
* Starts codeSection of the parser code
*/
private void startCodeSection() {
codeSection = new StringBuilder();
}
/**
* Adds the current code codeSection to antlr
*/
private void endCodeSection() {
addToAntlrCode(codeSection);
codeSection = new StringBuilder();
}
/**
* Starts antlr code for the given production
*
* @param ast
*/
private void startCodeSection(ASTNode ast) {
startCodeSection(ast.getClass().getSimpleName());
}
/**
* Starts antlr code for the production with the given name
*/
private void startCodeSection(String text) {
codeSection = new StringBuilder("\n // Start of '" + text + "'\n");
}
/**
* Ends antlr code for the given production
*
* @param ast
*/
private void endCodeSection(ASTNode ast) {
codeSection.append("// End of '" + ast.getClass().getSimpleName() + "'\n");
endCodeSection();
}
/**
* Adds the given code to the current codeSection
*/
private void addToCodeSection(String... code) {
Arrays.asList(code).forEach(s -> codeSection.append(s));
}
/**
* @return codeSection
*/
public StringBuilder getCodeSection() {
return this.codeSection;
}
/**
* Starts parser action
*/
private void startAction() {
action = new StringBuilder();
}
/**
* Adds code for parser action to the current code codeSection
*/
private void endAction() {
if (action.length() != 0) {
addToCodeSection("{", action.toString(), "}");
clearAction();
}
}
/**
* Adds code for parser action to the current code codeSection starting and
* ending with a new line
*/
private void endActionNewLine() {
if (action.length() != 0) {
addToCodeSection("{\n", action.toString(), "\n}");
clearAction();
}
}
/**
* Clears code for parser action
*/
private void clearAction() {
action = new StringBuilder();
}
private boolean isActionEmpty() {
return action.length() == 0;
}
/**
* @return action
*/
public StringBuilder getAction() {
return this.action;
}
/**
* Adds code to the parser action
*/
private void addToAction(String... code) {
Arrays.asList(code).forEach(s -> action.append(s));
}
}