Commit 26db32f8 authored by Johannes Roith's avatar Johannes Roith

- new AST model

- new error reporting
- new API
- replaced static variables with CupContext instances
- Lexer fixes
- various changes
parent 238678ee
This diff is collapsed.
package de.in.tum.www2.cup;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import de.in.tum.www2.cup.internal.*;
public class CupContext
{
private Boolean xmlActions = true;
private Boolean emitLocations = true;
private Boolean emitLRValues = true;
private Boolean showWarnings = true;
private ErrorManager errorManager;
private HashMap<String, Object> singletons = new HashMap<String, Object>();
public <T> T getForContext(Class<T> cls)
{
String name = cls.getName();
if (!singletons.containsKey(name)) {
System.out.println("setting up singleton for " + name + "!");
singletons.put(name, null); // just in case to prevent loops.
try {
Constructor<T> c = cls.getConstructor(
new Class[]{ CupContext.class });
Object inst = c.newInstance(this);
if (inst == null)
throw new RuntimeException("failed to create singleton!");
singletons.put(name, inst);
} catch (InstantiationException e) {
throw new RuntimeException("InstantiationException", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("IllegalAccessException", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("InvocationTargetException", e);
} catch (NoSuchMethodException e) {
throw new RuntimeException("NoSuchMethodException", e);
}
}
T result = (T) singletons.get(name);
if (result == null)
throw new RuntimeException("got null object from hashmap!");
return result;
}
// TODO: this stuff is only needed for the emitter and can be easily removed!
// -> could also be extracted from the AST.
public static Stack<String> import_list = new Stack<String>();
public static String parser_class_name;
public static String package_name;
public static String action_code;
public static String parser_code;
public static String init_code;
public static String scan_code;
public static String symbol_const_class_name;
public static int num_conflicts;
public static production start_production;
public Boolean getShowWarnings() {
return showWarnings;
}
public Boolean getEmitLRValues() {
return emitLRValues;
}
public Boolean getEmitLocations() {
return emitLocations;
}
public Boolean getXmlActions() {
return xmlActions;
}
public ErrorManager getErrorManager() {
return errorManager;
}
public CupContext (IErrorReporter er) {
this.errorManager = new ErrorManager(er);
}
}
package de.in.tum.www2.cup;
import java.io.FileInputStream;
import de.in.tum.www2.cup.ast.*;
import de.in.tum.www2.cup.internal.Parser;
public class CupParser
{
private CupContext context;
private Parser parser;
private ParserResult result;
public ParserResult getResult() {
return result;
}
public CupContext getContext() {
return context;
}
public CupParser(IErrorReporter er, FileInputStream inputStream) {
context = new CupContext(er);
parser = new Parser();
parser.init(context.getErrorManager(), context, inputStream);
}
public ParserResult parse() throws Exception {
if (result != null)
return result;
parser.parse();
result = parser.getResult();
return result;
}
}
package de.in.tum.www2.cup;
import java.io.Reader;
import java.io.IOException;
import java.io.InputStream;
import de.in.tum.www2.cup.ErrorManager;
import java_cup.runtime.ComplexSymbolFactory;
import de.in.tum.www2.cup.internal.Lexer;
public class CupScanner
{
private Lexer lexer;
public CupScanner(IErrorReporter er, InputStream is) {
ComplexSymbolFactory factory = new ComplexSymbolFactory();
ErrorManager errMan = new ErrorManager(er);
this.lexer = new Lexer(errMan, factory, is);
}
public CupScanner(IErrorReporter er, Reader r) {
ComplexSymbolFactory factory = new ComplexSymbolFactory();
ErrorManager errMan = new ErrorManager(er);
this.lexer = new Lexer(errMan, factory, r);
}
public java_cup.runtime.Symbol next_token() throws IOException {
return lexer.next_token();
}
}
package de.in.tum.www2.cup;
public class DefaultErrorReporter implements IErrorReporter
{
public void Warning(String msg) {
System.out.println("HELLO WARNING: " + msg);
}
public void Fatal(String msg) {
System.out.println("HELLO FATAL: " + msg);
}
public void Error(String msg) {
System.out.println("HELLO ERROR: " + msg);
}
}
package de.in.tum.www2.cup;
import java.io.FileInputStream;
import java.util.Enumeration;
import java_cup.runtime.*;
import de.in.tum.www2.cup.*;
import de.in.tum.www2.cup.analysis.LocationPatchVisitor;
import de.in.tum.www2.cup.ast.*;
import de.in.tum.www2.cup.internal.emit;
class Demo
{
public static void main(String[] blah) throws Exception {
IErrorReporter er = new DefaultErrorReporter();
FileInputStream input = new FileInputStream("/Users/jroith/testcup/test.cup");
CupParser parser = new CupParser(er, input);
ParserResult res = parser.parse();
CupContext context = parser.getContext();
System.out.println(res);
System.out.println("LocationPatchVisitor:");
LocationPatchVisitor visitor = new LocationPatchVisitor();
res.accept(visitor, null);
System.out.println("computing ...");
// FIX static:
// - terminal_set (EMPTY -> OK)
// - lalr_state (all, all_kernels, next_index)
// - parse_action_row (_size, reduction_count)
// - parse_reduce_row (_size)
// - terminal
// - non_terminal
// - production (_all, next_index)
// - emit
LALRResult lalrResult = LALRResult.Compute(context, context.start_production);
System.out.println(lalrResult.action_table);
System.out.println(lalrResult.reduce_table);
/*
lalr_state ordered[] = new lalr_state[lalr_state.number()];
for (Enumeration s = lalr_state.all(); s.hasMoreElements(); )
{
lalr_state st = (lalr_state)s.nextElement();
ordered[st.index()] = st;
}
System.err.println("===== Viable Prefix Recognizer =====");
for (int i = 0; i<lalr_state.number(); i++)
{
if (ordered[i] == start_state) System.err.print("START ");
System.err.println(ordered[i]);
System.err.println("-------------------");
}
}*/
/*
System.out.println("parser code: " + emit.parser_code);
System.out.println("init code: " + emit.init_code);
System.out.println("scan code: " + emit.scan_code);
// terminal
// non terminal
// precedence left
production prod = emit.start_production;
System.out.println(prod);
*/
System.out.println("done.");
}
}
package de.in.tum.www2.cup;
import java_cup.runtime.*;
public class ErrorManager
{
private IErrorReporter er;
private int error_count;
public int getErrorCount() {
return error_count;
}
public ErrorManager (IErrorReporter er) {
this.er = er;
}
public void Warning(String msg, Symbol sym) {
Warning (msg + "," + sym);
}
public void Warning(String msg) {
er.Warning(msg);
}
public void Fatal(String msg, Symbol sym) {
Fatal (msg + "," + sym);
}
public void Fatal(String msg) {
er.Fatal(msg);
}
public void Error(String msg, Symbol sym) {
Error (msg + "," + sym);
}
public void Error(String msg) {
er.Error(msg);
error_count++;
}
}
package de.in.tum.www2.cup;
public interface IErrorReporter
{
void Warning(String msg);
void Fatal(String msg);
void Error(String msg);
}
package de.in.tum.www2.cup;
import java.util.Enumeration;
import de.in.tum.www2.cup.internal.emit;
import de.in.tum.www2.cup.internal.internal_error;
import de.in.tum.www2.cup.internal.lalr_state;
import de.in.tum.www2.cup.internal.non_terminal;
import de.in.tum.www2.cup.internal.parse_action_table;
import de.in.tum.www2.cup.internal.parse_reduce_table;
import de.in.tum.www2.cup.internal.production;
public class LALRResult {
public lalr_state start_state;
public parse_action_table action_table;
public parse_reduce_table reduce_table;
private LALRResult() {
}
public static LALRResult Compute (CupContext context, production start_production) throws internal_error {
LALRResult result = new LALRResult();
non_terminal.compute_nullability(context);
non_terminal.compute_first_sets(context);
result.start_state = lalr_state.build_machine(context, start_production);
result.action_table = new parse_action_table(context);
result.reduce_table = new parse_reduce_table(context);
for (Enumeration st = lalr_state.all(context); st.hasMoreElements(); )
{
lalr_state lst = (lalr_state)st.nextElement();
lst.build_table_entries(result.action_table, result.reduce_table);
}
result.action_table.check_reductions();
int expect_conflicts = 0; // TODO: arbitrary?
// if we have more conflicts than we expected issue a message and die
if (context.num_conflicts > expect_conflicts)
{
System.out.println("*** More conflicts encountered than expected " +
"-- parser generation aborted");
// indicate the problem.
// we'll die on return, after clean up.
}
return result;
}
}
package de.in.tum.www2.cup.analysis;
public class ConflictCheckingVisitor<T> extends Visitor<T>
{
// This would probably imply porting the LALR part as well.
}
package de.in.tum.www2.cup.analysis;
public class CupGenVisitor<T> extends Visitor<T>
{
}
package de.in.tum.www2.cup.analysis;
import de.in.tum.www2.cup.ast.*;
public class LocationPatchVisitor extends Visitor<Object>
{
public void postVisit (Import node, Object data) {
System.out.println("hello from Import!");
}
}
package de.in.tum.www2.cup.analysis;
public class OldStructureBuildingVisitor<T> extends Visitor<T>
{
/*
// Start state in the overall state machine.
protected static lalr_state start_state;
// Resulting parse action table.
protected static parse_action_table action_table;
// Resulting reduce-goto table.
protected static parse_reduce_table reduce_table;
// Build the (internal) parser from the previously parsed specification.
protected static void build_parser() throws internal_error
{
// compute nullability of all non terminals
non_terminal.compute_nullability();
// compute first sets of all non terminals
non_terminal.compute_first_sets();
// build the LR viable prefix recognition machine
start_state = lalr_state.build_machine(emit.start_production);
// build the LR parser action and reduce-goto tables
action_table = new parse_action_table();
reduce_table = new parse_reduce_table();
for (Enumeration st = lalr_state.all(); st.hasMoreElements(); )
{
lalr_state lst = (lalr_state)st.nextElement();
lst.build_table_entries(action_table, reduce_table);
}
// check and warn for non-reduced productions
action_table.check_reductions();
// if we have more conflicts than we expected issue a message and die
if (emit.num_conflicts > expect_conflicts)
{
ErrorManager.getManager().emit_error("*** More conflicts encountered than expected " +
"-- parser generation aborted");
// indicate the problem.
// we'll die on return, after clean up.
}
}
// Call the emit routines necessary to write out the generated parser.
protected static void emit_parser() throws internal_error
{
emit.symbols(symbol_class_file, include_non_terms, sym_interface);
emit.parser(parser_class_file, action_table, reduce_table,
start_state.index(), emit.start_production, opt_compact_red,
suppress_scanner);
}
// Helper routine to optionally return a plural or non-plural ending.
// @param val the numerical value determining plurality.
protected static String plural(int val)
{
if (val == 1)
return "";
else
return "s";
}
protected static void emit_summary(boolean output_produced)
{
//unused symbols
System.err.println(" " + emit.unused_term + " terminal" +
plural(emit.unused_term) + " declared but not used.");
System.err.println(" " + emit.unused_non_term + " non-terminal" +
plural(emit.unused_term) + " declared but not used.");
//productions that didn't reduce
System.err.println(" " + emit.not_reduced + " production" +
plural(emit.not_reduced) + " never reduced.");
//conflicts
System.err.println(" " + emit.num_conflicts + " conflict" +
plural(emit.num_conflicts) + " detected" +
" (" + expect_conflicts + " expected).");
}
// Produce a (semi-) human readable dump of the complete viable prefix
// recognition state machine.
public static void dump_machine()
{
lalr_state ordered[] = new lalr_state[lalr_state.number()];
// put the states in sorted order for a nicer display
for (Enumeration s = lalr_state.all(); s.hasMoreElements(); )
{
lalr_state st = (lalr_state)s.nextElement();
ordered[st.index()] = st;
}
System.err.println("===== Viable Prefix Recognizer =====");
for (int i = 0; i<lalr_state.number(); i++)
{
if (ordered[i] == start_state) System.err.print("START ");
System.err.println(ordered[i]);
System.err.println("-------------------");
}
}
// Produce a (semi-) human readable dumps of the parse tables
public static void dump_tables()
{
System.err.println(action_table);
System.err.println(reduce_table);
}
*/
}
package de.in.tum.www2.cup.analysis;
public class ParseJavaVisitor<T> extends Visitor<T>
{
}
package de.in.tum.www2.cup.analysis;
public class RefResolutionVisitor extends Visitor<Object>
{
// fill declarations + production names into symbol tables
// resolve ProductionRef nodes and all identifiers.
}
package de.in.tum.www2.cup.analysis;
import de.in.tum.www2.cup.ast.*;
public abstract class Visitor<T>
{
public Boolean preVisit (ActionCodeBlock node, T data) { return true; }
public Boolean preVisit (ClassName node, T data) { return true; }
public Boolean preVisit (CodeBlock node, T data) { return true; }
public Boolean preVisit (Import node, T data) { return true; }
public Boolean preVisit (LabeledProductionRef node, T data) { return true; }
public Boolean preVisit (Name node, T data) { return true; }
public Boolean preVisit (NonTerminal node, T data) { return true; }
public Boolean preVisit (NonTerminalDeclaration node, T data) { return true; }
public Boolean preVisit (de.in.tum.www2.cup.ast.Package node, T data) { return true; }
public Boolean preVisit (ParserResult node, T data) { return true; }
public Boolean preVisit (Precedence node, T data) { return true; }
public Boolean preVisit (Production node, T data) { return true; }
public Boolean preVisit (ProductionRef node, T data) { return true; }
public Boolean preVisit (ProductionRight node, T data) { return true; }
public Boolean preVisit (StartWith node, T data) { return true; }
public Boolean preVisit (SymbolDeclaration node, T data) { return true; }
public Boolean preVisit (Terminal node, T data) { return true; }
public Boolean preVisit (TerminalDeclaration node, T data) { return true; }
public Boolean preVisit (TypedNonTerminalDeclaration node, T data) { return true; }
public Boolean preVisit (TypedTerminalDeclaration node, T data) { return true; }
public void postVisit (ActionCodeBlock node, T data) { }
public void postVisit (ClassName node, T data) { }
public void postVisit (CodeBlock node, T data) { }
public void postVisit (Import node, T data) { }
public void postVisit (LabeledProductionRef node, T data) { }
public void postVisit (Name node, T data) { }
public void postVisit (NonTerminal node, T data) { }
public void postVisit (NonTerminalDeclaration node, T data) { }
public void postVisit (de.in.tum.www2.cup.ast.Package node, T data) { }
public void postVisit (ParserResult node, T data) { }
public void postVisit (Precedence node, T data) { }
public void postVisit (Production node, T data) { }
public void postVisit (ProductionRef node, T data) { }
public void postVisit (ProductionRight node, T data) { }
public void postVisit (StartWith node, T data) { }
public void postVisit (SymbolDeclaration node, T data) { }
public void postVisit (Terminal node, T data) { }
public void postVisit (TerminalDeclaration node, T data) { }
public void postVisit (TypedNonTerminalDeclaration node, T data) { }
public void postVisit (TypedTerminalDeclaration node, T data) { }
}
package de.in.tum.www2.cup.ast;
import de.in.tum.www2.cup.analysis.Visitor;
import java_cup.runtime.ComplexSymbolFactory.Location;
import java_cup.runtime.ComplexSymbolFactory.ComplexSymbol;
public abstract class AbstractNode {
private ComplexSymbol begin;
private ComplexSymbol end;
public Location getBegin() {
if (begin == null)
return null;
return begin.xleft;
}
public Location getEnd() {
if (end == null)
return null;
return end.xright;
}
public AbstractNode (ComplexSymbol begin, ComplexSymbol end) {
this.begin = begin;
this.end = end;
}
public abstract <T> void accept(Visitor<T> visitor, T data);
protected abstract String getNodeName();
protected abstract void putDescription(StringBuilder builder);
private void appendLocation (StringBuilder builder,
ComplexSymbol symbol, Boolean right)
{
if (symbol != null) {
//builder.append("'" + symbol.getName() + "' ");
Location loc = (right) ? symbol.xright : symbol.xleft;
builder.append(loc.getLine());
builder.append("/");
builder.append(loc.getColumn());
} else {
builder.append("?");
}
}
public String toString(int indent) {
StringBuilder builder = new StringBuilder();
builder.append("{ ");
builder.append(getNodeName());
builder.append(" [");
appendLocation(builder, begin, false);
builder.append(" to ");
appendLocation(builder, end, true);
builder.append("] : ");
putDescription(builder);
builder.append(" }");
return builder.toString();
}
@Override
public String toString() {
return toString(0);
}
}