package com.sap.furcas.parsergenerator.tcs.generator; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; import com.sap.furcas.modeladaptation.emf.lookup.QueryBasedEcoreMetaModelLookUp; import com.sap.furcas.parsergenerator.GenerationErrorHandler; import com.sap.furcas.parsergenerator.GrammarGenerationException; import com.sap.furcas.parsergenerator.GrammarGenerationSourceConfiguration; import com.sap.furcas.parsergenerator.GrammarGenerationTargetConfiguration; import com.sap.furcas.parsergenerator.TCSSyntaxContainerBean; import com.sap.furcas.parsergenerator.tcs.t2m.ModelBasedTCSGrammarGenerator; import com.sap.furcas.parsergenerator.tcs.t2m.grammar.GenerationReport; import com.sap.furcas.runtime.common.exceptions.ModelAdapterException; import com.sap.furcas.runtime.common.exceptions.ParserInvokationException; import com.sap.furcas.runtime.parser.ParsingError; import com.sap.furcas.runtime.parser.exceptions.SyntaxParsingException; import com.sap.furcas.runtime.parser.impl.ObservableInjectingParser; /** * Reads a syntax definition given as a file and generates a ANTLR gramamr for it. * */ public class GrammarGenerator { /** * Takes a syntax definition in file form, parses that file and then writes a corresponding ANTLR grammar to the given grammar * file. * * @throws GrammarGenerationException */ public static void buildGrammar(GrammarGenerationSourceConfiguration sourceConfiguration, GrammarGenerationTargetConfiguration targetConfiguration, GenerationErrorHandler errorhandler, TCSSyntaxContainerBean syntaxBean) throws GrammarGenerationException { buildGrammar(sourceConfiguration, targetConfiguration, errorhandler, /* use default parser super class */null, syntaxBean); } /** * Takes a syntax definition in file form, parses that file and then writes a corresponding ANTLR grammar to the given grammar * file. * * @throws GrammarGenerationException */ public static void buildGrammar(GrammarGenerationSourceConfiguration sourceConfiguration, GrammarGenerationTargetConfiguration targetConfiguration, GenerationErrorHandler errorhandler, Class<? extends ObservableInjectingParser> parserSuperClass, TCSSyntaxContainerBean syntaxBean) throws GrammarGenerationException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { generateGrammar(sourceConfiguration, targetConfiguration, parserSuperClass, errorhandler, outputStream, syntaxBean); } catch (SyntaxParsingException e) { handleSyntaxParsingException(errorhandler, e); } catch (ModelAdapterException e) { throw new GrammarGenerationException("Model adapter failed", e); } catch (IOException e) { throw new GrammarGenerationException("Grammar generation failed with IO error", e); } catch (ParserInvokationException e) { throw new GrammarGenerationException("Failed to instantiate the TCS Parser", e); } finally { try { outputStream.close(); } catch (IOException e) { throw new GrammarGenerationException("Grammar generation failed with IO error", e); } } } private static void generateGrammar(GrammarGenerationSourceConfiguration sourceConfiguration, GrammarGenerationTargetConfiguration targetConfiguration, Class<? extends ObservableInjectingParser> parserSuperClass, GenerationErrorHandler errorhandler, ByteArrayOutputStream outputStream, TCSSyntaxContainerBean syntaxBean) throws ParserInvokationException, SyntaxParsingException, IOException, ModelAdapterException, GrammarGenerationException { QueryBasedEcoreMetaModelLookUp metamodelLookup = new QueryBasedEcoreMetaModelLookUp(sourceConfiguration.getResourceSet(), sourceConfiguration.getReferenceScope()); ModelBasedTCSGrammarGenerator modelBasedGenerator = new ModelBasedTCSGrammarGenerator(outputStream, metamodelLookup, targetConfiguration.getParserTargetPackageName(), syntaxBean); GenerationReport report = modelBasedGenerator.generateGrammar(sourceConfiguration.getResourceSet(), sourceConfiguration.getReferenceScope(), parserSuperClass); boolean hasErrors = checkForErrorsAndReport(report, errorhandler); if (!hasErrors) { File grammarFile = targetConfiguration.getGrammarTargetFile(); writeGrammarToFile(grammarFile, outputStream); } } private static boolean checkForErrorsAndReport(GenerationReport report, GenerationErrorHandler errorhandler) { errorhandler.info("FURCAS Generation Report for Textual Concrete Syntax: " + report.getSyntaxName()); boolean hasErrors = false; if (report.getWarnings() != null && report.getWarnings().size() > 0) { for (ParsingError warning : report.getWarnings()) { errorhandler.warning(warning); } } if (report.getErrors() != null && report.getErrors().size() > 0) { hasErrors = true; for (ParsingError error : report.getErrors()) { errorhandler.error(error); } } if (hasErrors) { errorhandler.info("Finished with errors."); } else { errorhandler.info("Finished successfully."); } return hasErrors; } private static void writeGrammarToFile(File grammarFile, ByteArrayOutputStream grammarDataStream) throws IOException { if (grammarFile.exists()) { grammarFile.delete(); } grammarFile.getParentFile().mkdirs(); grammarFile.createNewFile(); FileOutputStream outputStream = new FileOutputStream(grammarFile); outputStream.write(grammarDataStream.toByteArray()); outputStream.close(); } private static void handleSyntaxParsingException(GenerationErrorHandler errorhandler, SyntaxParsingException e) throws GrammarGenerationException { List<ParsingError> errors = e.getErrorList(); if (errors != null) { for (ParsingError parsingError : errors) { errorhandler.fatalError(parsingError); } } else { throw new GrammarGenerationException("No Parsing Errors delievered with " + e.getMessage()); } } }