/*
* ******************************************************************************
* 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;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import com.google.common.base.Joiner;
import de.monticore.codegen.GeneratorHelper;
import de.monticore.codegen.mc2cd.TransformationHelper;
import de.monticore.codegen.parser.antlr.AntlrTool;
import de.monticore.codegen.parser.antlr.Grammar2Antlr;
import de.monticore.generating.GeneratorEngine;
import de.monticore.generating.GeneratorSetup;
import de.monticore.generating.templateengine.GlobalExtensionManagement;
import de.monticore.grammar.MCGrammarInfo;
import de.monticore.grammar.grammar._ast.ASTMCGrammar;
import de.monticore.grammar.symboltable.MCGrammarSymbol;
import de.monticore.io.paths.IterablePath;
import de.monticore.symboltable.Scope;
import de.se_rwth.commons.Names;
import de.se_rwth.commons.logging.Log;
/**
* TODO: Write me!
*
* @author (last commit) $Author$
* @version $Revision$, $Date$
*/
public class ParserGenerator {
public static final String PARSER_PACKAGE = "_parser";
public static final String PARSER_WRAPPER = "Parser";
public static final String LOG = "ParserGenerator";
/**
* Code generation from grammar ast to an antlr compatible file format
* @param glex
*
* @param astGrammar - grammar AST
* @param targetFile - target file
*/
public static void generateParser(GlobalExtensionManagement glex, ASTMCGrammar astGrammar, Scope symbolTable,
IterablePath handcodedPath, File targetFile) {
if (astGrammar.isComponent()) {
Log.info("No parser generation for the grammar " + astGrammar.getName(), LOG);
return;
}
Log.debug("Start parser generation for the grammar " + astGrammar.getName(), LOG);
final GeneratorSetup setup = new GeneratorSetup(targetFile);
String qualifiedGrammarName = astGrammar.getPackage().isEmpty()
? astGrammar.getName()
: Joiner.on('.').join(Names.getQualifiedName(astGrammar.getPackage()),
astGrammar.getName());
MCGrammarSymbol grammarSymbol = symbolTable.<MCGrammarSymbol> resolve(
qualifiedGrammarName, MCGrammarSymbol.KIND).orElse(null);
Log.errorIfNull(grammarSymbol, "0xA4034 Grammar " + qualifiedGrammarName
+ " can't be resolved in the scope " + symbolTable);
// TODO: grammarInfo as parameter for this method?
MCGrammarInfo grammarInfo = new MCGrammarInfo(grammarSymbol);
ParserGeneratorHelper genHelper = new ParserGeneratorHelper(astGrammar, grammarInfo);
glex.setGlobalValue("parserHelper", genHelper);
glex.setGlobalValue("nameHelper", new Names());
setup.setGlex(glex);
final Path filePath = Paths.get(Names.getPathFromPackage(genHelper.getParserPackage()),
astGrammar.getName() + "Antlr.g4");
new GeneratorEngine(setup).generate("parser.Parser", filePath, astGrammar,
new Grammar2Antlr(genHelper,
grammarInfo));
// construct parser, lexer, ... (antlr),
String gFile = Paths.get(targetFile.getAbsolutePath(), filePath.toString()).toString();
Log.debug("Start Antlr generation for the antlr file " + gFile, LOG);
AntlrTool antlrTool = new AntlrTool(new String[] {}, grammarSymbol,
Paths.get(targetFile.getAbsolutePath(),
Names.getPathFromPackage(genHelper.getParserPackage())));
antlrTool.createParser(gFile);
Log.debug("End parser generation for the grammar " + astGrammar.getName(), LOG);
}
/**
* Code generation from grammar ast to an antlr compatible file format
* @param glex
*
* @param astGrammar - grammar AST
* @param targetFile - target file
*/
public static void generateParserWrappers(GlobalExtensionManagement glex, ASTMCGrammar astGrammar, Scope symbolTable,
IterablePath handcodedPath, File targetFile) {
if (astGrammar.isComponent()) {
return;
}
final GeneratorSetup setup = new GeneratorSetup(targetFile);
String qualifiedGrammarName = astGrammar.getPackage().isEmpty()
? astGrammar.getName()
: Joiner.on('.').join(Names.getQualifiedName(astGrammar.getPackage()),
astGrammar.getName());
MCGrammarSymbol grammarSymbol = symbolTable.<MCGrammarSymbol> resolve(
qualifiedGrammarName, MCGrammarSymbol.KIND).orElse(null);
Log.errorIfNull(grammarSymbol, "0xA4035 Grammar " + qualifiedGrammarName
+ " can't be resolved in the scope " + symbolTable);
// ParserGeneratorHelper genHelper = new ParserGeneratorHelper(astGrammar,
// grammarSymbol);
// glex.setGlobalValue("parserHelper", genHelper);
glex.setGlobalValue("nameHelper", new Names());
setup.setGlex(glex);
final GeneratorEngine generator = new GeneratorEngine(setup);
// Generate wrapper
String parserWrapperSuffix = TransformationHelper.existsHandwrittenClass(handcodedPath,
GeneratorHelper.getDotPackageName(
GeneratorHelper.getPackageName(astGrammar, PARSER_PACKAGE)) + astGrammar.getName()
+ PARSER_WRAPPER) ? TransformationHelper.GENERATED_CLASS_SUFFIX : "";
final Path path = Paths.get(
Names.getPathFromPackage(GeneratorHelper.getPackageName(astGrammar, PARSER_PACKAGE)),
astGrammar.getName() + "Parser" + parserWrapperSuffix + ".java");
generator.generate("parser.MCParser", path, astGrammar, astGrammar,
parserWrapperSuffix, grammarSymbol.getProdsWithInherited().values());
}
private ParserGenerator() {
// noninstantiable
}
}