/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package openbook.tools.converter; import java.io.PrintStream; import java.util.StringTokenizer; import openbook.tools.parser.JavaParser; import org.antlr.runtime.CommonToken; import org.antlr.runtime.Token; import org.antlr.runtime.debug.BlankDebugEventListener; /** * A token processor to render the ANTLR tokens. * * This token processor is notified as ANTLR parses every token. * This processor controls a {@linkplain TokenRenderer renderer} * that renders the token. * * @author Pinaki Poddar * */ public class ParseTokenListener extends BlankDebugEventListener { private int currentLine = 0; private int backtracking = 0; private int decision; private TokenRenderer _renderer; private PrintStream _stream; /** * By default, uses a {@linkplain PlainTokenRenderer}. */ ParseTokenListener() { this(new PlainTokenRenderer()); } /** * Uses the given renderer and outputs to System output. * * @param renderer a renderer to render the tokens. */ ParseTokenListener(TokenRenderer renderer) { this(renderer, System.out); } /** * Uses the given renderer and given outputs stream. * * @param renderer a renderer to render the tokens. * @param stream a output stream where the rendered strings are streamed. */ ParseTokenListener(TokenRenderer renderer, PrintStream stream) { _renderer = renderer; _stream = stream; } @Override public void enterDecision(int d) { backtracking += 1; decision = d; } @Override public void exitDecision(int i) { backtracking -= 1; } /** * A regular token is delegated to the renderer for a string representation * and the resultant string is sent to the output stream. */ @Override public void consumeToken(Token token) { if (backtracking > 0) return; changeLine(token.getLine()); _stream.print(_renderer.render(decision, token)); } /** * Hidden tokens are tokens that are not processed at lexical processing * stage. The most important hidden token for rendering are the tokens * that represent multi-line or single line comments. The multi-line * comments must be broken into individual lines for line numbering to * remain consistent. * */ @Override public void consumeHiddenToken(Token token) { if (this.backtracking > 0 && currentLine != 0) return; int type = token.getType(); if (type == JavaParser.COMMENT || type == JavaParser.LINE_COMMENT) { StringTokenizer linebreaker = new StringTokenizer(token.getText(), "\r\n", false); int i = 0; while (linebreaker.hasMoreTokens()) { Token dummy = new CommonToken(JavaParser.COMMENT, linebreaker.nextToken()); changeLine(token.getLine() + i); _stream.print(_renderer.render(decision, dummy)); i++; } } else { changeLine(token.getLine()); _stream.print(_renderer.render(decision, token)); } } /** * If the given line is different than the current line, then asks the * renderer to end the current line and start a new line. Otherwise, does nothing. * * @param newline */ void changeLine(int newline) { if (newline == currentLine) return; _stream.print(_renderer.endLine(currentLine)); _stream.print(_renderer.newLine(newline)); currentLine = newline; } }