package parsing; import java.io.IOException; import java.util.Observable; import java.util.Stack; import org.antlr.v4.runtime.ANTLRFileStream; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.BailErrorStrategy; import org.antlr.v4.runtime.DefaultErrorStrategy; import org.antlr.v4.runtime.Lexer; import org.antlr.v4.runtime.Parser; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.misc.ParseCancellationException; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.ParseTreeListener; import org.antlr.v4.runtime.tree.ParseTreeWalker; import ast.ASTNode; import ast.ASTNodeBuilder; import ast.statements.CompoundStatement; import ast.walking.ASTWalkerEvent; abstract public class ANTLRParserDriver extends Observable { // TODO: This class does two things: // * It is a driver for the ANTLRParser, i.e., the parser // that creates ParseTrees from Strings. It can also already // 'walk' the ParseTree to create ASTs. // * It is an AST provider in that it will notify watchers // when ASTs are ready. // We should split this into two classes. public Stack<ASTNodeBuilder> builderStack = new Stack<ASTNodeBuilder>(); public TokenSubStream stream; public String filename; private Parser antlrParser; private ParseTreeListener listener; private CommonParserContext context = null; abstract public ParseTree parseTokenStreamImpl(TokenSubStream tokens); abstract public Lexer createLexer(ANTLRInputStream input); public ANTLRParserDriver() { super(); } public void parseAndWalkFile(String filename) throws ParserException { TokenSubStream stream = createTokenStreamFromFile(filename); initializeContextWithFile(filename, stream); ParseTree tree = parseTokenStream(stream); walkTree(tree); } public void parseAndWalkTokenStream(TokenSubStream tokens) throws ParserException { filename = ""; stream = tokens; ParseTree tree = parseTokenStream(tokens); walkTree(tree); } public ParseTree parseAndWalkString(String input) throws ParserException { ParseTree tree = parseString(input); walkTree(tree); return tree; } public ParseTree parseTokenStream(TokenSubStream tokens) throws ParserException { ParseTree returnTree = parseTokenStreamImpl(tokens); if (returnTree == null) throw new ParserException(); return returnTree; } public ParseTree parseString(String input) throws ParserException { char[] charArray = input.toCharArray(); ANTLRInputStream inputStream = new ANTLRInputStream(charArray, charArray.length); Lexer lex = createLexer(inputStream); TokenSubStream tokens = new TokenSubStream(lex); ParseTree tree = parseTokenStream(tokens); return tree; } protected TokenSubStream createTokenStreamFromFile(String filename) throws ParserException { ANTLRInputStream input; try { input = new ANTLRFileStream(filename); } catch (IOException e) { throw new ParserException(); } Lexer lexer = createLexer(input); TokenSubStream tokens = new TokenSubStream(lexer); return tokens; } protected void walkTree(ParseTree tree) { ParseTreeWalker walker = new ParseTreeWalker(); walker.walk(getListener(), tree); } protected void initializeContextWithFile(String filename, TokenSubStream stream) { setContext(new CommonParserContext()); getContext().filename = filename; getContext().stream = stream; initializeContext(getContext()); } protected boolean isRecognitionException(RuntimeException ex) { return ex.getClass() == ParseCancellationException.class && ex.getCause() instanceof RecognitionException; } protected void setLLStarMode(Parser parser) { parser.removeErrorListeners(); // parser.addErrorListener(ConsoleErrorListener.INSTANCE); parser.setErrorHandler(new DefaultErrorStrategy()); // parser.getInterpreter().setPredictionMode(PredictionMode.LL); } protected void setSLLMode(Parser parser) { // parser.getInterpreter().setPredictionMode(PredictionMode.SLL); parser.removeErrorListeners(); parser.setErrorHandler(new BailErrorStrategy()); } public void initializeContext(CommonParserContext context) { filename = context.filename; stream = context.stream; } public void setStack(Stack<ASTNodeBuilder> aStack) { builderStack = aStack; } // ////////////////// public void begin() { notifyObserversOfBegin(); } public void end() { notifyObserversOfEnd(); } private void notifyObserversOfBegin() { ASTWalkerEvent event = new ASTWalkerEvent(ASTWalkerEvent.eventID.BEGIN); setChanged(); notifyObservers(event); } private void notifyObserversOfEnd() { ASTWalkerEvent event = new ASTWalkerEvent(ASTWalkerEvent.eventID.END); setChanged(); notifyObservers(event); } public void notifyObserversOfUnitStart(ParserRuleContext ctx) { ASTWalkerEvent event = new ASTWalkerEvent( ASTWalkerEvent.eventID.START_OF_UNIT); event.ctx = ctx; event.filename = filename; setChanged(); notifyObservers(event); } public void notifyObserversOfUnitEnd(ParserRuleContext ctx) { ASTWalkerEvent event = new ASTWalkerEvent( ASTWalkerEvent.eventID.END_OF_UNIT); event.ctx = ctx; event.filename = filename; setChanged(); notifyObservers(event); } public void notifyObserversOfItem(ASTNode aItem) { ASTWalkerEvent event = new ASTWalkerEvent( ASTWalkerEvent.eventID.PROCESS_ITEM); event.item = aItem; event.itemStack = builderStack; setChanged(); notifyObservers(event); } public CompoundStatement getResult() { return (CompoundStatement) builderStack.peek().getItem(); } public Parser getAntlrParser() { return antlrParser; } public void setAntlrParser(Parser aParser) { antlrParser = aParser; } public ParseTreeListener getListener() { return listener; } public void setListener(ParseTreeListener listener) { this.listener = listener; } public CommonParserContext getContext() { return context; } public void setContext(CommonParserContext context) { this.context = context; } }