fixes for sonarqube

This commit is contained in:
Jörg Prante 2016-10-25 22:27:05 +02:00
parent 85bcb906ed
commit a00c9708a8
61 changed files with 2838 additions and 719 deletions

View file

@ -1,5 +1,5 @@
plugins { plugins {
id "org.sonarqube" version '2.1-rc1' id "org.sonarqube" version '2.2'
} }
ext { ext {
@ -41,5 +41,12 @@ dependencies {
wagon 'org.apache.maven.wagon:wagon-ssh-external:2.10' wagon 'org.apache.maven.wagon:wagon-ssh-external:2.10'
} }
test {
testLogging {
showStandardStreams = false
exceptionFormat = 'full'
}
}
apply from: 'gradle/publish.gradle' apply from: 'gradle/publish.gradle'
apply from: 'gradle/sonarqube.gradle' apply from: 'gradle/sonarqube.gradle'

View file

@ -52,8 +52,8 @@ task sonaTypeUpload(type: Upload) {
} }
licenses { licenses {
license { license {
name 'The Apache License, Version 2.0' name 'BSD 3-Clause License'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt' url 'https://opensource.org/licenses/BSD-3-Clause'
} }
} }
} }
@ -77,6 +77,15 @@ task hbzUpload(type: Upload) {
authentication(userName: hbzUserName, privateKey: hbzPrivateKey) authentication(userName: hbzUserName, privateKey: hbzPrivateKey)
} }
pom.project { pom.project {
name name
description description
packaging 'jar'
inceptionYear '2012'
url scmUrl
organization {
name 'xbib'
url 'http://xbib.org'
}
developers { developers {
developer { developer {
id 'jprante' id 'jprante'
@ -86,15 +95,14 @@ task hbzUpload(type: Upload) {
} }
} }
scm { scm {
url 'https://github.com/xbib/groovy-webapp' url scmUrl
connection 'scm:git:git://github.com/xbib/groovy-webapp.git' connection scmConnection
developerConnection 'scm:git:git://github.com/xbib/groovy-webapp.git' developerConnection scmDeveloperConnection
} }
inceptionYear '2016'
licenses { licenses {
license { license {
name 'The Apache License, Version 2.0' name 'BSD 3-Clause License'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt' url 'https://opensource.org/licenses/BSD-3-Clause'
} }
} }
} }

View file

@ -30,7 +30,7 @@ jacocoTestReport {
sonarqube { sonarqube {
properties { properties {
property "sonar.projectName", "jacc" property "sonar.projectName", "${project.group} ${project.name}"
property "sonar.sourceEncoding", "UTF-8" property "sonar.sourceEncoding", "UTF-8"
property "sonar.language", "java" property "sonar.language", "java"
property "sonar.sources", "src/main/java" property "sonar.sources", "src/main/java"

View file

@ -1,6 +1,5 @@
package org.xbib.jacc; package org.xbib.jacc;
import org.xbib.jacc.compiler.Failure;
import org.xbib.jacc.compiler.Handler; import org.xbib.jacc.compiler.Handler;
import org.xbib.jacc.compiler.Phase; import org.xbib.jacc.compiler.Phase;
import org.xbib.jacc.grammar.Grammar; import org.xbib.jacc.grammar.Grammar;
@ -12,12 +11,11 @@ import java.io.IOException;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Writer; import java.io.Writer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
/** /**
* *
*/ */
abstract class Output extends Phase { abstract class AbstractOutput extends Phase {
protected Grammar grammar; protected Grammar grammar;
protected int numTs; protected int numTs;
@ -27,9 +25,9 @@ abstract class Output extends Phase {
int numStates; int numStates;
JaccTables tables; JaccTables tables;
JaccResolver resolver; JaccResolver resolver;
Settings settings; JaccSettings jaccSettings;
Output(Handler handler, JaccJob jaccjob) { AbstractOutput(Handler handler, JaccJob jaccjob) {
super(handler); super(handler);
tables = jaccjob.getTables(); tables = jaccjob.getTables();
machine = tables.getMachine(); machine = tables.getMachine();
@ -39,7 +37,7 @@ abstract class Output extends Phase {
numSyms = grammar.getNumSyms(); numSyms = grammar.getNumSyms();
numStates = machine.getNumStates(); numStates = machine.getNumStates();
resolver = jaccjob.getResolver(); resolver = jaccjob.getResolver();
settings = jaccjob.getSettings(); jaccSettings = jaccjob.getJaccSettings();
} }
static void indent(Writer writer, int i, String[] as) throws IOException { static void indent(Writer writer, int i, String[] as) throws IOException {
@ -60,24 +58,17 @@ abstract class Output extends Phase {
} }
static void datestamp(Writer writer) throws IOException { static void datestamp(Writer writer) throws IOException {
writer.write("// Output created by jacc 2.1.0 on " + LocalDateTime.now() + "\n"); writer.write("// Output created by jacc 2.1.0\n");
} }
public void write(String s) throws IOException { public void write(String s) throws IOException {
Writer writer = null; File file = new File(s);
try { File parent = file.getParentFile();
File file = new File(s); if (parent != null && !parent.exists() && !parent.mkdirs()) {
File parent = file.getParentFile(); return;
if (!parent.exists()) {
boolean mkdirs = parent.mkdirs();
}
writer = new OutputStreamWriter(new FileOutputStream(s), StandardCharsets.UTF_8);
write(writer);
} catch (IOException ioexception) {
report(new Failure("Cannot write to file \"" + s + "\""));
} }
if (writer != null) { try (Writer writer = new OutputStreamWriter(new FileOutputStream(s), StandardCharsets.UTF_8)) {
writer.close(); write(writer);
} }
} }

View file

@ -8,18 +8,18 @@ import org.xbib.jacc.grammar.Machine;
*/ */
class Conflicts { class Conflicts {
private int type; private final int type;
private int arg1; private final int arg1;
private int arg2; private final int arg2;
private Grammar.Symbol sym; private final Grammar.Symbol sym;
private Conflicts next; private Conflicts next;
private Conflicts(int i, int j, int k, Grammar.Symbol symbol, Conflicts conflicts) { private Conflicts(int i, int j, int k, Grammar.Symbol symbol, Conflicts conflicts) {
type = i; this.type = i;
arg1 = j; this.arg1 = j;
arg2 = k; this.arg2 = k;
sym = symbol; this.sym = symbol;
next = conflicts; this.next = conflicts;
} }
static Conflicts sr(int i, int j, Grammar.Symbol symbol, Conflicts conflicts) { static Conflicts sr(int i, int j, Grammar.Symbol symbol, Conflicts conflicts) {
@ -43,7 +43,8 @@ class Conflicts {
return conflicts; return conflicts;
} }
static String describe(Machine machine, int i, Conflicts conflicts) { static String describe(Machine machine, int i, Conflicts c) {
Conflicts conflicts = c;
if (conflicts == null) { if (conflicts == null) {
return ""; return "";
} }

View file

@ -52,6 +52,7 @@ class Fixity {
return obj instanceof Fixity && equalsFixity((Fixity) obj); return obj instanceof Fixity && equalsFixity((Fixity) obj);
} }
@Override
public int hashCode() { public int hashCode() {
return assoc ^ prec; return assoc ^ prec;
} }

View file

@ -4,198 +4,248 @@ import org.xbib.jacc.compiler.ConsoleHandler;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Writer; import java.io.Writer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* *
*/ */
public class Jacc { public class Jacc {
private static final Logger logger = Logger.getLogger(Jacc.class.getName());
private String className;
private InputStream inputStream;
private InputStream errorDiagnostics;
private InputStream parserInputs;
private OutputStream outputStream;
private String suffix;
private JaccSettings jaccSettings;
private boolean enableParserOutput;
private boolean enableTokenOutput;
private boolean enableVerboseMachineDescription;
private boolean includeCalculations;
private boolean includeStateNumbers;
private String dir;
public Jacc() { public Jacc() {
this.className = null;
this.inputStream = null;
this.suffix = ".jacc";
this.jaccSettings = new JaccSettings();
this.enableParserOutput = true;
this.enableTokenOutput = true;
this.enableVerboseMachineDescription = false;
this.includeCalculations = false;
this.errorDiagnostics = null;
this.parserInputs = null;
this.includeStateNumbers = false;
this.dir = null;
this.outputStream = System.out;
}
public void setIncludeCalculations(boolean includeCalculations) {
this.includeCalculations = includeCalculations;
}
public void setEnableParserOutput(boolean enableParserOutput) {
this.enableParserOutput = enableParserOutput;
}
public void setEnableTokenOutput(boolean enableTokenOutput) {
this.enableTokenOutput = enableTokenOutput;
}
public void setEnableVerboseMachineDescription(boolean enableVerboseMachineDescription) {
this.enableVerboseMachineDescription = enableVerboseMachineDescription;
}
public void setMachineType(MachineType machineType) {
jaccSettings.setMachineType(machineType);
}
public void setIncludeStateNumbers(boolean includeStateNumbers) {
this.includeStateNumbers = includeStateNumbers;
}
public void setName(String name) {
this.className = name;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
public InputStream getInputStream() {
return inputStream;
}
public void setErrorDiagnostics(InputStream errorDiagnostics) {
this.errorDiagnostics = errorDiagnostics;
}
public InputStream getErrorDiagnostics() {
return errorDiagnostics;
}
public void setParserInputs(InputStream parserInputs) {
this.parserInputs = parserInputs;
}
public InputStream getParserInputs() {
return parserInputs;
}
public String getSuffix() {
return suffix;
}
public void setDir(String dir) {
this.dir = dir;
}
public void setOutputStream(OutputStream outputStream) {
this.outputStream = outputStream;
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
NameList namelist = null; Jacc jacc = new Jacc();
String s = ".jacc";
Settings settings = new Settings();
boolean flag = true;
boolean flag1 = true;
boolean flag2 = false;
boolean flag4 = false;
NameList namelist1 = null;
NameList namelist2 = null;
boolean flag5 = false;
String dir = null;
Writer writer = new BufferedWriter(new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
label0:
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
String s1 = args[i]; String arg = args[i];
if (s1.startsWith("-")) { if (arg.startsWith("-")) {
if (s1.length() == 1) { if (arg.length() == 1) {
usage("Missing command line options"); usage("Missing command line options");
} }
int j = 1; int j = 1;
do { while (j < arg.length()) {
if (j >= s1.length()) { switch (arg.charAt(j)) {
continue label0; case 'f':
} jacc.setIncludeCalculations(true);
switch (s1.charAt(j)) {
case 102: // 'f'
flag4 = true;
break; break;
case 'p':
case 112: // 'p' jacc.setEnableParserOutput(false);
flag = false;
break; break;
case 't':
case 116: // 't' jacc.setEnableTokenOutput(false);
flag1 = false;
break; break;
case 'v':
case 118: // 'v' jacc.setEnableVerboseMachineDescription(true);
flag2 = true;
break; break;
case '0':
case 48: // '0' jacc.setMachineType(MachineType.LR0);
settings.setMachineType(0);
break; break;
case 's':
case 115: // 's' jacc.setMachineType(MachineType.SLR1);
settings.setMachineType(1);
break; break;
case 'a':
case 97: // 'a' jacc.setMachineType(MachineType.LALR1);
settings.setMachineType(2);
break; break;
case 'n':
case 101: // 'e' jacc.setIncludeStateNumbers(true);
break;
case 'e':
if (i + 1 >= args.length) { if (i + 1 >= args.length) {
usage("Missing filename for -e option"); usage("Missing filename for -e option");
} }
namelist1 = new NameList(args[++i], namelist1); jacc.setErrorDiagnostics(Files.newInputStream(Paths.get(args[++i])));
break; break;
case 'r':
case 114: // 'r'
if (i + 1 >= args.length) { if (i + 1 >= args.length) {
usage("Missing filename for -r option"); usage("Missing filename for -r option");
} }
namelist2 = new NameList(args[++i], namelist2); jacc.setParserInputs(Files.newInputStream(Paths.get(args[++i])));
break; break;
case 110: // 'n'
flag5 = true;
break;
case 'd': case 'd':
if (i + 1 >= args.length) { if (i + 1 >= args.length) {
usage("Missing directory for -d option"); usage("Missing directory for -d option");
} }
dir = args[++i]; jacc.setDir(args[++i]);
break;
case 'o':
if (i + 1 >= args.length) {
usage("Missing filename for -o option");
}
jacc.setOutputStream(Files.newOutputStream(Paths.get(args[++i])));
break; break;
default: default:
usage("Unrecognized command line option " + s1.charAt(j)); usage("Unrecognized command line option " + arg.charAt(j));
break; break;
} }
j++; j++;
} while (true); }
} }
if (!s1.endsWith(s)) { if (!arg.endsWith(jacc.getSuffix())) {
usage("Input file must have \"" + s + "\" suffix"); usage("Input file must have \"" + jacc.getSuffix() + "\" suffix");
} else { } else {
namelist = new NameList(s1, namelist); jacc.setInputStream(Files.newInputStream(Paths.get(arg)));
} }
} }
if (jacc.getInputStream() == null) {
if (namelist == null) {
usage("No input file(s) specified"); usage("No input file(s) specified");
} else {
jacc.execute();
} }
ConsoleHandler simplehandler = new ConsoleHandler(); }
String s2 = namelist.getFirst();
int k = 1 + Math.max(s2.lastIndexOf('\\'), s2.lastIndexOf('/')); public void execute() throws IOException {
dir = dir == null ? s2.substring(0, k) : dir; Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
String s4 = s2.substring(k, s2.length() - s.length()); ConsoleHandler consoleHandler = new ConsoleHandler();
final JaccJob job = new JaccJob(simplehandler, writer, settings); if (dir == null) {
NameList.visit(namelist, new NameList.Visitor() { dir = ".";
public void visit(String s5) throws IOException { }
job.parseGrammarFile(s5); if (!dir.endsWith("/")) {
} dir = dir + "/";
}); }
final JaccJob job = new JaccJob(consoleHandler, writer, jaccSettings);
job.parseGrammarStream(inputStream);
job.buildTables(); job.buildTables();
settings.fillBlanks(s4); jaccSettings.fillBlanks(className);
NameList.visit(namelist1, new NameList.Visitor() { if (errorDiagnostics != null) {
public void visit(String s5) throws IOException { job.readErrorExamples(errorDiagnostics);
job.readErrorExamples(s5); }
if (consoleHandler.getNumFailures() == 0) {
if (enableParserOutput) {
(new ParserOutput(consoleHandler, job)).write(dir + jaccSettings.getClassName() + ".java");
} }
}); if (enableTokenOutput) {
if (simplehandler.getNumFailures() > 0) { (new TokensOutput(consoleHandler, job)).write(dir + jaccSettings.getInterfaceName() + ".java");
return;
}
if (flag) {
(new ParserOutput(simplehandler, job)).write(dir + settings.getClassName() + ".java");
}
if (flag1) {
(new TokensOutput(simplehandler, job)).write(dir + settings.getInterfaceName() + ".java");
}
if (flag2) {
(new TextOutput(simplehandler, job, flag4)).write(dir + s4 + ".output");
}
final boolean showState = flag5;
NameList.visit(namelist2, new NameList.Visitor() {
public void visit(String s5) throws IOException {
job.readRunExample(s5, showState);
} }
}); if (enableVerboseMachineDescription) {
(new TextOutput(consoleHandler, job, includeCalculations)).write(dir + jaccSettings.getClassName() + ".output");
}
if (parserInputs != null) {
job.readRunExample(parserInputs, includeStateNumbers);
}
} else {
writer.write("There were failures.\n");
}
writer.close();
} }
private static void usage(String s) { private static void usage(String s) {
System.err.println(s); logger.log(Level.INFO, s);
System.err.println("usage: jacc [options] file.jacc ..."); String mesg = "usage: jacc [options] file.jacc ...\n" +
System.err.println("options (individually, or in combination):"); "options (individually, or in combination):\n" +
System.err.println(" -p do not generate parser"); " -p do not generate parser\n" +
System.err.println(" -t do not generate token specification"); " -t do not generate token specification\n" +
System.err.println(" -v output text description of machine"); " -v output text description of machine\n" +
System.err.println(" -f show first/follow sets (with -h or -v)"); " -f show first/follow sets (with -h or -v)\n" +
System.err.println(" -a treat as LALR(1) grammar (default)"); " -a treat as LALR(1) grammar (default)\n" +
System.err.println(" -s treat as SLR(1) grammar"); " -s treat as SLR(1) grammar\n" +
System.err.println(" -0 treat as LR(0) grammar"); " -0 treat as LR(0) grammar\n" +
System.err.println(" -r file run parser on input in file"); " -r file run parser on input in file\n" +
System.err.println(" -n show state numbers in parser output"); " -n show state numbers in parser output\n" +
System.err.println(" -e file read error cases from file"); " -e file read error cases from file\n" +
System.err.println(" -d dir output files to directory"); " -d dir output files to directory\n" +
System.exit(1); " -o file name of output file for parser runs\n";
} logger.log(Level.INFO, mesg);
private static class NameList {
String name;
NameList names;
NameList(String s, NameList namelist) {
name = s;
names = namelist;
}
static void visit(NameList namelist, Visitor visitor) throws IOException {
if (namelist != null) {
visit(namelist.names, visitor);
visitor.visit(namelist.name);
}
}
String getFirst() {
NameList namelist;
namelist = this;
while (namelist.names != null) {
namelist = namelist.names;
}
return namelist.name;
}
interface Visitor {
void visit(String s) throws IOException;
}
} }
} }

View file

@ -0,0 +1,11 @@
package org.xbib.jacc;
/**
*
*/
public class JaccException extends Exception {
public JaccException(String message) {
super(message);
}
}

View file

@ -13,14 +13,18 @@ import org.xbib.jacc.grammar.Parser;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.io.Writer; import java.io.Writer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
/**
*
*/
class JaccJob extends Phase { class JaccJob extends Phase {
private Settings settings; private JaccSettings jaccSettings;
private JaccParser parser; private JaccParser parser;
@ -30,15 +34,15 @@ class JaccJob extends Phase {
private Writer out; private Writer out;
JaccJob(Handler handler, Writer out, Settings settings) { JaccJob(Handler handler, Writer out, JaccSettings jaccSettings) {
super(handler); super(handler);
this.out = out; this.out = out;
this.settings = settings; this.jaccSettings = jaccSettings;
this.parser = new JaccParser(handler, settings); this.parser = new JaccParser(handler, jaccSettings);
} }
Settings getSettings() { JaccSettings getJaccSettings() {
return settings; return jaccSettings;
} }
JaccTables getTables() { JaccTables getTables() {
@ -49,23 +53,62 @@ class JaccJob extends Phase {
return resolver; return resolver;
} }
private JaccLexer lexerFromFile(String s) { void parseGrammarStream(InputStream inputStream) throws IOException {
JaccLexer jacclexer; JaccLexer jacclexer = lexerFromInputStream(inputStream);
try { if (jacclexer != null) {
Reader filereader = new InputStreamReader(new FileInputStream(s), StandardCharsets.UTF_8); parser.parse(jacclexer);
jacclexer = new JaccLexer(getHandler(), new JavaSource(getHandler(), s, filereader)); jacclexer.close();
jacclexer.nextToken();
return jacclexer;
} catch (IOException e) {
report(new Failure("Could not open file \"" + s + "\""));
return null;
} }
} }
void parseGrammarFile(String s) throws IOException { private JaccLexer lexerFromFile(String s) throws IOException {
JaccLexer jacclexer;
Reader filereader = new InputStreamReader(new FileInputStream(s), StandardCharsets.UTF_8);
jacclexer = new JaccLexer(getHandler(), new JavaSource(getHandler(), filereader));
jacclexer.nextToken();
return jacclexer;
}
private JaccLexer lexerFromInputStream(InputStream inputStream) throws IOException {
JaccLexer jacclexer;
Reader filereader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
jacclexer = new JaccLexer(getHandler(), new JavaSource(getHandler(), filereader));
jacclexer.nextToken();
return jacclexer;
}
void readErrorExamples(String s) throws IOException {
out.write("Reading error examples from \"" + s + "\"");
JaccLexer jacclexer = lexerFromFile(s); JaccLexer jacclexer = lexerFromFile(s);
if (jacclexer != null) { if (jacclexer != null) {
parser.parse(jacclexer); parser.parseErrorExamples(jacclexer, this);
jacclexer.close();
}
}
void readErrorExamples(InputStream inputStream) throws IOException {
JaccLexer jacclexer = lexerFromInputStream(inputStream);
if (jacclexer != null) {
parser.parseErrorExamples(jacclexer, this);
jacclexer.close();
}
}
void readRunExample(String s, boolean flag) throws IOException {
out.write("Running example from \"" + s + "\"]\n");
JaccLexer jacclexer = lexerFromFile(s);
if (jacclexer != null) {
runExample(parser.parseSymbols(jacclexer), flag);
jacclexer.close();
}
}
void readRunExample(InputStream inputStream, boolean flag) throws IOException {
out.write("Running example from input stream\n");
JaccLexer jacclexer = lexerFromInputStream(inputStream);
if (jacclexer != null) {
runExample(parser.parseSymbols(jacclexer), flag);
jacclexer.close();
} }
} }
@ -74,9 +117,9 @@ class JaccJob extends Phase {
if (grammar == null || !allDeriveFinite(grammar)) { if (grammar == null || !allDeriveFinite(grammar)) {
return; return;
} }
LookaheadMachine lookaheadmachine = settings.makeMachine(grammar); LookaheadMachine lookaheadmachine = jaccSettings.makeMachine(grammar);
resolver = new JaccResolver(lookaheadmachine); this.resolver = new JaccResolver(lookaheadmachine);
tables = new JaccTables(lookaheadmachine, resolver); this.tables = new JaccTables(lookaheadmachine, resolver);
if (tables.getProdUnused() > 0) { if (tables.getProdUnused() > 0) {
report(new Warning(tables.getProdUnused() + " rules never reduced")); report(new Warning(tables.getProdUnused() + " rules never reduced"));
} }
@ -93,7 +136,7 @@ class JaccJob extends Phase {
Finitary finitary = grammar.getFinitary(); Finitary finitary = grammar.getFinitary();
boolean flag = true; boolean flag = true;
for (int i = 0; i < grammar.getNumNTs(); i++) { for (int i = 0; i < grammar.getNumNTs(); i++) {
if (!finitary.at(i)) { if (!finitary.isAt(i)) {
flag = false; flag = false;
report(new Failure("No finite strings can be derived for " + report(new Failure("No finite strings can be derived for " +
grammar.getNonterminal(i))); grammar.getNonterminal(i)));
@ -102,15 +145,7 @@ class JaccJob extends Phase {
return flag; return flag;
} }
void readRunExample(String s, boolean flag) throws IOException { private void runExample(int[] ai, boolean flag) throws IOException {
out.write("Running example from \"" + s + "\"]\n");
JaccLexer jacclexer = lexerFromFile(s);
if (jacclexer != null) {
runExample(parser.parseSymbols(jacclexer), flag);
}
}
private void runExample(int ai[], boolean flag) throws IOException {
Grammar grammar = parser.getGrammar(); Grammar grammar = parser.getGrammar();
Parser parser1 = new Parser(tables, ai); Parser parser1 = new Parser(tables, ai);
out.write("start "); out.write("start ");
@ -142,30 +177,22 @@ class JaccJob extends Phase {
} while (true); } while (true);
} }
void readErrorExamples(String s) throws IOException { void errorExample(Position position, String s, int[] ai) {
out.write("Reading error examples from \"" + s + "\""); Parser p = new Parser(tables, ai);
JaccLexer jacclexer = lexerFromFile(s);
if (jacclexer != null) {
parser.parseErrorExamples(jacclexer, this);
}
}
void errorExample(Position position, String s, int ai[]) {
Parser parser1 = new Parser(tables, ai);
int i; int i;
do { do {
i = parser1.step(); i = p.step();
} while (i != 0 && i != 1); } while (i != 0 && i != 1);
if (i == 0) { if (i == 0) {
report(new Warning(position, "Example for \"" + s + "\" does not produce an error")); report(new Warning(position, "Example for \"" + s + "\" does not produce an error"));
} else { } else {
Grammar grammar = tables.getMachine().getGrammar(); Grammar grammar = tables.getMachine().getGrammar();
int j = parser1.getNextSymbol(); int j = p.getNextSymbol();
if (grammar.isNonterminal(j)) { if (grammar.isNonterminal(j)) {
report(new Warning(position, report(new Warning(position,
"Example for \"" + s + "\" reaches an error at the nonterminal " + grammar.getSymbol(j))); "Example for \"" + s + "\" reaches an error at the nonterminal " + grammar.getSymbol(j)));
} else { } else {
int k = parser1.getState(); int k = p.getState();
if (!tables.errorAt(k, j)) { if (!tables.errorAt(k, j)) {
report(new Failure(position, "Error example results in internal error")); report(new Failure(position, "Error example results in internal error"));
} else { } else {

View file

@ -21,74 +21,69 @@ class JaccLexer extends SourceLexer implements JaccTokens {
@Override @Override
public int nextToken() throws IOException { public int nextToken() throws IOException {
do { while (true) {
skipWhitespace(); skipWhitespace();
markPosition(); markPosition();
lexemeText = null; lexemeText = null;
switch (c) { switch (c) {
case -1: case -1:
return token = ENDINPUT; token = ENDINPUT;
return token;
case 58: // ':' case ':':
nextChar(); nextChar();
return token = COLON; token = COLON;
return token;
case 59: // ';' case ';':
nextChar(); nextChar();
return token = SEMI; token = SEMI;
return token;
case 124: // '|' case '|':
nextChar(); nextChar();
return token = BAR; token = BAR;
return token;
case 60: // '<' case '<':
nextChar(); nextChar();
return token = TOPEN; token = TOPEN;
return token;
case 62: // '>' case '>':
nextChar(); nextChar();
return token = TCLOSE; token = TCLOSE;
return token;
case 91: // '[' case '[':
nextChar(); nextChar();
return token = BOPEN; token = BOPEN;
return token;
case 93: // ']' case ']':
nextChar(); nextChar();
return token = BCLOSE; token = BCLOSE;
return token;
case 46: // '.' case '.':
nextChar(); nextChar();
return token = DOT; token = DOT;
return token;
case 37: // '%' case '%':
if (directive() != -1) { if (directive() != -1) {
return token; return token;
} }
break; break;
case '"':
case 34: // '"'
if (string() != -1) { if (string() != -1) {
return token; return token;
} }
break; break;
case '\'':
case 39: // '\''
if (literal() != -1) { if (literal() != -1) {
return token; return token;
} }
break; break;
case '{':
case 123: // '{'
if (action() != -1) { if (action() != -1) {
return token; return token;
} }
break; break;
case '/':
case 47: // '/'
skipComment(); skipComment();
break; break;
default: default:
if (Character.isJavaIdentifierStart((char) c)) { if (Character.isJavaIdentifierStart((char) c)) {
return identifier(); return identifier();
@ -100,7 +95,7 @@ class JaccLexer extends SourceLexer implements JaccTokens {
nextChar(); nextChar();
break; break;
} }
} while (true); }
} }
String readWholeLine() throws IOException { String readWholeLine() throws IOException {
@ -176,64 +171,68 @@ class JaccLexer extends SourceLexer implements JaccTokens {
nextChar(); nextChar();
} while (c != -1 && Character.isJavaIdentifierPart((char) c)); } while (c != -1 && Character.isJavaIdentifierPart((char) c));
lexemeText = line.substring(i, col); lexemeText = line.substring(i, col);
return token = IDENT; token = IDENT;
return token;
} }
private int directive() throws IOException { private int directive() throws IOException {
nextChar(); nextChar();
if (c == 37) { if (c == 37) {
nextChar(); nextChar();
return token = MARK; token = MARK;
return token;
} }
if (Character.isJavaIdentifierStart((char) c)) { if (Character.isJavaIdentifierStart((char) c)) {
identifier(); identifier();
if (lexemeText.equals("token")) { switch (lexemeText) {
return token = TOKEN; case "token":
} token = TOKEN;
if (lexemeText.equals("type")) { return token;
return token = TYPE; case "type":
} token = TYPE;
if (lexemeText.equals("prec")) { return token;
return token = PREC; case "prec":
} token = PREC;
if (lexemeText.equals("left")) { return token;
return token = LEFT; case "left":
} token = LEFT;
if (lexemeText.equals("right")) { return token;
return token = RIGHT; case "right":
} token = RIGHT;
if (lexemeText.equals("nonassoc")) { return token;
return token = NONASSOC; case "nonassoc":
} token = NONASSOC;
if (lexemeText.equals("start")) { return token;
return token = START; case "start":
} token = START;
if (lexemeText.equals("package")) { return token;
return token = PACKAGE; case "package":
} token = PACKAGE;
if (lexemeText.equals("extends")) { return token;
return token = EXTENDS; case "extends":
} token = EXTENDS;
if (lexemeText.equals("implements")) { return token;
return token = IMPLEMENTS; case "implements":
} token = IMPLEMENTS;
if (lexemeText.equals("semantic")) { return token;
return token = SEMANTIC; case "semantic":
} token = SEMANTIC;
if (lexemeText.equals("get")) { return token;
return token = GETTOKEN; case "get":
} token = GETTOKEN;
if (lexemeText.equals("next")) { return token;
return token = NEXTTOKEN; case "next":
} token = NEXTTOKEN;
if (lexemeText.equals("class")) { return token;
return token = CLASS; case "class":
} token = CLASS;
if (lexemeText.equals("interface")) { return token;
return token = INTERFACE; case "interface":
} else { token = INTERFACE;
report(new Failure(getPos(), "Unrecognized directive")); return token;
return ERROR; default:
report(new Failure(getPos(), "Unrecognized directive"));
return ERROR;
} }
} }
if (c == 123) { if (c == 123) {
@ -256,13 +255,15 @@ class JaccLexer extends SourceLexer implements JaccTokens {
if (c == 125) { if (c == 125) {
lexemeText = endBuffer(sb, i, col - 1); lexemeText = endBuffer(sb, i, col - 1);
nextChar(); nextChar();
return token = CODE; token = CODE;
return token;
} }
} }
if (c == -1) { if (c == -1) {
report(new Failure(getPos(), "Code fragment terminator %} not found")); report(new Failure(getPos(), "Code fragment terminator %} not found"));
lexemeText = endBuffer(sb, i, col); lexemeText = endBuffer(sb, i, col);
return token = CODE; token = CODE;
return token;
} }
if (c == 10) { if (c == 10) {
if (sb == null) { if (sb == null) {
@ -304,7 +305,8 @@ class JaccLexer extends SourceLexer implements JaccTokens {
} while (k >= 0); } while (k >= 0);
lexemeText = line.substring(i, col); lexemeText = line.substring(i, col);
lastLiteral = j; lastLiteral = j;
return token = INTLIT; token = INTLIT;
return token;
} }
private int string() { private int string() {
@ -323,7 +325,8 @@ class JaccLexer extends SourceLexer implements JaccTokens {
} else { } else {
report(new Warning(getPos(), "Missing \" on string literal")); report(new Warning(getPos(), "Missing \" on string literal"));
} }
return token = STRLIT; token = STRLIT;
return token;
} }
private int literal() { private int literal() {
@ -346,23 +349,26 @@ class JaccLexer extends SourceLexer implements JaccTokens {
report(new Warning(getPos(), "Missing ' on character literal")); report(new Warning(getPos(), "Missing ' on character literal"));
} }
lexemeText = line.substring(i, col); lexemeText = line.substring(i, col);
return token = CHARLIT; token = CHARLIT;
return token;
} }
private void escapeChar() { private void escapeChar() {
nextChar(); nextChar();
switch (c) { switch (c) {
case 34: // '"' case '"':
case 39: // '\'' case '\'':
case 92: // '\\' case '\\':
case 98: // 'b' case 'b':
case 102: // 'f' case 'f':
case 110: // 'n' case 'n':
case 114: // 'r' case 'r':
case 116: // 't' case 't':
lastLiteral = c; lastLiteral = c;
nextChar(); nextChar();
return; return;
default:
break;
} }
int i = Character.digit((char) c, 8); int i = Character.digit((char) c, 8);
if (i >= 0) { if (i >= 0) {
@ -387,7 +393,8 @@ class JaccLexer extends SourceLexer implements JaccTokens {
if (--j == 0) { if (--j == 0) {
nextChar(); nextChar();
lexemeText = endBuffer(sb, i, col); lexemeText = endBuffer(sb, i, col);
return token = ACTION; token = ACTION;
return token;
} }
} else { } else {
if (c == 123) { if (c == 123) {
@ -397,7 +404,8 @@ class JaccLexer extends SourceLexer implements JaccTokens {
if (c == -1) { if (c == -1) {
report(new Failure(getPos(), "Unterminated action")); report(new Failure(getPos(), "Unterminated action"));
lexemeText = endBuffer(sb, i, col); lexemeText = endBuffer(sb, i, col);
return token = ACTION; token = ACTION;
return token;
} }
if (c == 10) { if (c == 10) {
if (sb == null) { if (sb == null) {

View file

@ -8,38 +8,43 @@ import org.xbib.jacc.compiler.Warning;
import org.xbib.jacc.grammar.Grammar; import org.xbib.jacc.grammar.Grammar;
import java.io.IOException; import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* *
*/ */
class JaccParser extends Phase implements JaccTokens { class JaccParser extends Phase implements JaccTokens {
private Settings settings; private static final Logger logger = Logger.getLogger(JaccParser.class.getName());
private final JaccSettings jaccSettings;
private final NamedJaccSymbols terminals;
private final NamedJaccSymbols nonterms;
private final NumJaccSymbols literals;
private int seqNo; private int seqNo;
private JaccLexer lexer; private JaccLexer lexer;
private int precedence; private int precedence;
private NamedJaccSymbols terminals; private JaccSymbol startSymbol;
private NamedJaccSymbols nonterms;
private NumJaccSymbols literals; JaccParser(Handler handler, JaccSettings jaccSettings) {
private JaccSymbol start;
JaccParser(Handler handler, Settings settings1) {
super(handler); super(handler);
seqNo = 1; this.jaccSettings = jaccSettings;
precedence = 0; this.terminals = new NamedJaccSymbols();
settings = settings1; this.nonterms = new NamedJaccSymbols();
terminals = new NamedJaccSymbols(); this.literals = new NumJaccSymbols();
nonterms = new NamedJaccSymbols(); this.seqNo = 1;
literals = new NumJaccSymbols(); this.precedence = 0;
start = null; this.startSymbol = null;
} }
public Grammar getGrammar() { public Grammar getGrammar() {
try { try {
JaccSymbol ajaccsymbol[]; JaccSymbol[] ajaccsymbol;
JaccProd ajaccprod[][]; JaccProd[][] ajaccprod;
int i = nonterms.getSize(); int i = nonterms.getSize();
int j = terminals.getSize() + literals.getSize() + 1; int j = terminals.getSize() + literals.getSize() + 1;
if (i == 0 || start == null) { if (i == 0 || startSymbol == null) {
report(new Failure("No nonterminals defined")); report(new Failure("No nonterminals defined"));
return null; return null;
} }
@ -58,11 +63,11 @@ class JaccParser extends Phase implements JaccTokens {
ajaccsymbol[i + l].setNum(k++); ajaccsymbol[i + l].setNum(k++);
} }
int i1 = 0; int i1 = 0;
do { while (true) {
if (i1 >= i) { if (i1 >= i) {
break; break;
} }
if (ajaccsymbol[i1] == start) { if (ajaccsymbol[i1] == startSymbol) {
if (i1 > 0) { if (i1 > 0) {
JaccSymbol jaccsymbol = ajaccsymbol[0]; JaccSymbol jaccsymbol = ajaccsymbol[0];
ajaccsymbol[0] = ajaccsymbol[i1]; ajaccsymbol[0] = ajaccsymbol[i1];
@ -71,7 +76,7 @@ class JaccParser extends Phase implements JaccTokens {
break; break;
} }
i1++; i1++;
} while (true); }
for (int j1 = 0; j1 < ajaccsymbol.length; j1++) { for (int j1 = 0; j1 < ajaccsymbol.length; j1++) {
ajaccsymbol[j1].setTokenNo(j1); ajaccsymbol[j1].setTokenNo(j1);
} }
@ -83,7 +88,8 @@ class JaccParser extends Phase implements JaccTokens {
} }
} }
return new Grammar(ajaccsymbol, ajaccprod); return new Grammar(ajaccsymbol, ajaccprod);
} catch (Exception e) { } catch (JaccException e) {
logger.log(Level.SEVERE, e.getMessage(), e);
report(new Failure("Internal problem " + e.getMessage())); report(new Failure("Internal problem " + e.getMessage()));
return null; return null;
} }
@ -101,8 +107,8 @@ class JaccParser extends Phase implements JaccTokens {
String s; String s;
if (jacclexer.getToken() == 1) { if (jacclexer.getToken() == 1) {
while ((s = jacclexer.readWholeLine()) != null) { while ((s = jacclexer.readWholeLine()) != null) {
settings.addPostText(s); jaccSettings.addPostText(s);
settings.addPostText("\n"); jaccSettings.addPostText("\n");
} }
} }
} }
@ -112,7 +118,7 @@ class JaccParser extends Phase implements JaccTokens {
int[] parseSymbols(JaccLexer jacclexer) throws IOException { int[] parseSymbols(JaccLexer jacclexer) throws IOException {
lexer = jacclexer; lexer = jacclexer;
SymList symlist = null; SymList symlist = null;
do { while (true) {
JaccSymbol jaccsymbol = parseDefinedSymbol(); JaccSymbol jaccsymbol = parseDefinedSymbol();
if (jaccsymbol == null) { if (jaccsymbol == null) {
if (jacclexer.getToken() != 0) { if (jacclexer.getToken() != 0) {
@ -123,12 +129,12 @@ class JaccParser extends Phase implements JaccTokens {
} }
symlist = new SymList(jaccsymbol, symlist); symlist = new SymList(jaccsymbol, symlist);
jacclexer.nextToken(); jacclexer.nextToken();
} while (true); }
} }
void parseErrorExamples(JaccLexer jacclexer, JaccJob jaccjob) throws IOException { void parseErrorExamples(JaccLexer jacclexer, JaccJob jaccjob) throws IOException {
lexer = jacclexer; lexer = jacclexer;
do { while (true) {
if (jacclexer.getToken() != 5) { if (jacclexer.getToken() != 5) {
break; break;
} }
@ -139,7 +145,7 @@ class JaccParser extends Phase implements JaccTokens {
report(new Warning(jacclexer.getPos(), "A colon was expected here")); report(new Warning(jacclexer.getPos(), "A colon was expected here"));
} }
int i; int i;
do { while (true) {
Position position = jacclexer.getPos(); Position position = jacclexer.getPos();
SymList symlist = null; SymList symlist = null;
JaccSymbol jaccsymbol; JaccSymbol jaccsymbol;
@ -147,14 +153,14 @@ class JaccParser extends Phase implements JaccTokens {
symlist = new SymList(jaccsymbol, symlist); symlist = new SymList(jaccsymbol, symlist);
jacclexer.nextToken(); jacclexer.nextToken();
} }
int ai[] = SymList.toIntArray(symlist); int[] ai = SymList.toIntArray(symlist);
jaccjob.errorExample(position, s, ai); jaccjob.errorExample(position, s, ai);
i = jacclexer.getToken(); i = jacclexer.getToken();
if (i != 124) { if (i != 124) {
break; break;
} }
jacclexer.nextToken(); jacclexer.nextToken();
} while (true); }
if (i != 0) { if (i != 0) {
if (i != 59) { if (i != 59) {
report(new Failure(jacclexer.getPos(), "Unexpected token; a semicolon was expected here")); report(new Failure(jacclexer.getPos(), "Unexpected token; a semicolon was expected here"));
@ -166,7 +172,7 @@ class JaccParser extends Phase implements JaccTokens {
jacclexer.nextToken(); jacclexer.nextToken();
} }
} }
} while (true); }
if (jacclexer.getToken() != 0) { if (jacclexer.getToken() != 0) {
report(new Failure(jacclexer.getPos(), "Unexpected token; ignoring the rest of this file")); report(new Failure(jacclexer.getPos(), "Unexpected token; ignoring the rest of this file"));
} }
@ -175,11 +181,13 @@ class JaccParser extends Phase implements JaccTokens {
private void parseDefinitions() throws IOException { private void parseDefinitions() throws IOException {
boolean flag = false; boolean flag = false;
do { while (true) {
switch (lexer.getToken()) { switch (lexer.getToken()) {
case 0: // '\0' case 0: // '\0'
case 1: // '\001' case 1: // '\001'
return; return;
default:
break;
} }
if (parseDefinition()) { if (parseDefinition()) {
flag = false; flag = false;
@ -190,88 +198,73 @@ class JaccParser extends Phase implements JaccTokens {
} }
lexer.nextToken(); lexer.nextToken();
} }
} while (true); }
} }
private boolean parseDefinition() throws IOException { private boolean parseDefinition() throws IOException {
switch (lexer.getToken()) { switch (lexer.getToken()) {
case 2: // '\002' case CODE:
settings.addPreText(lexer.getLexeme()); jaccSettings.addPreText(lexer.getLexeme());
lexer.nextToken(); lexer.nextToken();
return true; return true;
case TOKEN:
case 8: // '\b'
parseTokenDefn(); parseTokenDefn();
return true; return true;
case TYPE:
case 9: // '\t'
parseTypeDefn(); parseTypeDefn();
return true; return true;
case LEFT:
case 11: // '\013'
parseFixityDefn(Fixity.left(precedence++)); parseFixityDefn(Fixity.left(precedence++));
return true; return true;
case NONASSOC:
case 13: // '\r'
parseFixityDefn(Fixity.nonass(precedence++)); parseFixityDefn(Fixity.nonass(precedence++));
return true; return true;
case RIGHT:
case 12: // '\f'
parseFixityDefn(Fixity.right(precedence++)); parseFixityDefn(Fixity.right(precedence++));
return true; return true;
case START:
case 14: // '\016'
parseStart(); parseStart();
return true; return true;
case CLASS:
case 16: // '\020' jaccSettings.setClassName(parseIdent(lexer.getLexeme(), jaccSettings.getClassName()));
settings.setClassName(parseIdent(lexer.getLexeme(), settings.getClassName()));
return true; return true;
case INTERFACE:
case 17: // '\021' jaccSettings.setInterfaceName(parseIdent(lexer.getLexeme(), jaccSettings.getInterfaceName()));
settings.setInterfaceName(parseIdent(lexer.getLexeme(), settings.getInterfaceName()));
return true; return true;
case PACKAGE:
case 15: // '\017' jaccSettings.setPackageName(parseDefnQualName(lexer.getLexeme(), jaccSettings.getPackageName()));
settings.setPackageName(parseDefnQualName(lexer.getLexeme(), settings.getPackageName()));
return true; return true;
case EXTENDS:
case 18: // '\022' jaccSettings.setExtendsName(parseDefnQualName(lexer.getLexeme(), jaccSettings.getExtendsName()));
settings.setExtendsName(parseDefnQualName(lexer.getLexeme(), settings.getExtendsName()));
return true; return true;
case IMPLEMENTS:
case 19: // '\023'
lexer.nextToken(); lexer.nextToken();
String s = parseQualName(); String s = parseQualName();
if (s != null) { if (s != null) {
settings.addImplementsNames(s); jaccSettings.addImplementsNames(s);
} }
return true; return true;
case SEMANTIC:
case 20: // '\024' jaccSettings.setTypeName(parseDefnQualName(lexer.getLexeme(), jaccSettings.getTypeName()));
settings.setTypeName(parseDefnQualName(lexer.getLexeme(), settings.getTypeName()));
if (lexer.getToken() == 58) { if (lexer.getToken() == 58) {
settings.setGetSemantic(lexer.readCodeLine()); jaccSettings.setGetSemantic(lexer.readCodeLine());
lexer.nextToken(); lexer.nextToken();
} }
return true; return true;
case GETTOKEN:
case 21: // '\025' jaccSettings.setGetToken(lexer.readCodeLine());
settings.setGetToken(lexer.readCodeLine());
lexer.nextToken(); lexer.nextToken();
return true; return true;
case NEXTTOKEN:
case 22: // '\026' jaccSettings.setNextToken(lexer.readCodeLine());
settings.setNextToken(lexer.readCodeLine());
lexer.nextToken(); lexer.nextToken();
return true; return true;
case IDENT:
case 3: // '\003' case CHARLIT:
case 4: // '\004' case STRLIT:
case 5: // '\005' case INTLIT:
case 6: // '\006' case ACTION:
case 7: // '\007' case PREC:
case 10: // '\n'
default: default:
return false; return false;
} }
@ -284,8 +277,8 @@ class JaccParser extends Phase implements JaccTokens {
if (jaccsymbol == null) { if (jaccsymbol == null) {
report(new Failure(position, "Missing start symbol")); report(new Failure(position, "Missing start symbol"));
} else { } else {
if (start == null) { if (startSymbol == null) {
start = jaccsymbol; startSymbol = jaccsymbol;
} else { } else {
report(new Failure(position, "Multiple %start definitions are not permitted")); report(new Failure(position, "Multiple %start definitions are not permitted"));
} }
@ -323,7 +316,7 @@ class JaccParser extends Phase implements JaccTokens {
Position position = lexer.getPos(); Position position = lexer.getPos();
String s = optionalType(); String s = optionalType();
int i = 0; int i = 0;
do { while (true) {
JaccSymbol jaccsymbol = parseTerminal(); JaccSymbol jaccsymbol = parseTerminal();
if (jaccsymbol == null) { if (jaccsymbol == null) {
if (i == 0) { if (i == 0) {
@ -334,14 +327,14 @@ class JaccParser extends Phase implements JaccTokens {
addType(jaccsymbol, s); addType(jaccsymbol, s);
lexer.nextToken(); lexer.nextToken();
i++; i++;
} while (true); }
} }
private void parseTypeDefn() throws IOException { private void parseTypeDefn() throws IOException {
Position position = lexer.getPos(); Position position = lexer.getPos();
String s = optionalType(); String s = optionalType();
int i = 0; int i = 0;
do { while (true) {
JaccSymbol jaccsymbol = parseSymbol(); JaccSymbol jaccsymbol = parseSymbol();
if (jaccsymbol == null) { if (jaccsymbol == null) {
if (i == 0) { if (i == 0) {
@ -352,14 +345,14 @@ class JaccParser extends Phase implements JaccTokens {
addType(jaccsymbol, s); addType(jaccsymbol, s);
lexer.nextToken(); lexer.nextToken();
i++; i++;
} while (true); }
} }
private void parseFixityDefn(Fixity fixity) throws IOException { private void parseFixityDefn(Fixity fixity) throws IOException {
Position position = lexer.getPos(); Position position = lexer.getPos();
String s = optionalType(); String s = optionalType();
int i = 0; int i = 0;
do { while (true) {
JaccSymbol jaccsymbol = parseTerminal(); JaccSymbol jaccsymbol = parseTerminal();
if (jaccsymbol == null) { if (jaccsymbol == null) {
if (i == 0) { if (i == 0) {
@ -371,7 +364,7 @@ class JaccParser extends Phase implements JaccTokens {
addType(jaccsymbol, s); addType(jaccsymbol, s);
lexer.nextToken(); lexer.nextToken();
i++; i++;
} while (true); }
} }
private String optionalType() throws IOException { private String optionalType() throws IOException {
@ -380,24 +373,24 @@ class JaccParser extends Phase implements JaccTokens {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
label1: label1:
{ {
if (lexer.nextToken() != 60) { if (lexer.nextToken() != TOPEN) {
break label0; break label0;
} }
lexer.nextToken(); lexer.nextToken();
sb.append(parseQualName()); sb.append(parseQualName());
do { while (true) {
if (lexer.getToken() != 91) { if (lexer.getToken() != BOPEN) {
break label1; break label1;
} }
if (lexer.nextToken() != 93) { if (lexer.nextToken() != BCLOSE) {
break; break;
} }
lexer.nextToken(); lexer.nextToken();
sb.append("[]"); sb.append("[]");
} while (true); }
report(new Failure(lexer.getPos(), "Missing ']' in array type")); report(new Failure(lexer.getPos(), "Missing ']' in array type"));
} }
if (lexer.getToken() == 62) { if (lexer.getToken() == TCLOSE) {
lexer.nextToken(); lexer.nextToken();
} else if (sb.length() > 0) { } else if (sb.length() > 0) {
report(new Failure(lexer.getPos(), "Missing `>' in type specification")); report(new Failure(lexer.getPos(), "Missing `>' in type specification"));
@ -422,8 +415,8 @@ class JaccParser extends Phase implements JaccTokens {
private void parseGrammar() throws IOException { private void parseGrammar() throws IOException {
JaccSymbol jaccsymbol; JaccSymbol jaccsymbol;
while ((jaccsymbol = parseLhs()) != null) { while ((jaccsymbol = parseLhs()) != null) {
if (start == null) { if (startSymbol == null) {
start = jaccsymbol; startSymbol = jaccsymbol;
} }
jaccsymbol.addProduction(parseRhs()); jaccsymbol.addProduction(parseRhs());
for (; lexer.getToken() == 124; jaccsymbol.addProduction(parseRhs())) { for (; lexer.getToken() == 124; jaccsymbol.addProduction(parseRhs())) {
@ -472,7 +465,7 @@ class JaccParser extends Phase implements JaccTokens {
private JaccProd parseRhs() throws IOException { private JaccProd parseRhs() throws IOException {
Fixity fixity = null; Fixity fixity = null;
SymList symlist = null; SymList symlist = null;
do { while (true) {
while (lexer.getToken() == 10) { while (lexer.getToken() == 10) {
lexer.nextToken(); lexer.nextToken();
JaccSymbol jaccsymbol = parseSymbol(); JaccSymbol jaccsymbol = parseSymbol();
@ -497,7 +490,7 @@ class JaccParser extends Phase implements JaccTokens {
} }
symlist = new SymList(jaccsymbol1, symlist); symlist = new SymList(jaccsymbol1, symlist);
lexer.nextToken(); lexer.nextToken();
} while (true); }
String s = null; String s = null;
Position position = null; Position position = null;
if (lexer.getToken() == 7) { if (lexer.getToken() == 7) {
@ -505,7 +498,7 @@ class JaccParser extends Phase implements JaccTokens {
position = lexer.getPos(); position = lexer.getPos();
lexer.nextToken(); lexer.nextToken();
} }
JaccSymbol ajaccsymbol[] = SymList.toArray(symlist); JaccSymbol[] ajaccsymbol = SymList.toArray(symlist);
return new JaccProd(fixity, ajaccsymbol, position, s, seqNo++); return new JaccProd(fixity, ajaccsymbol, position, s, seqNo++);
} }
@ -515,7 +508,7 @@ class JaccParser extends Phase implements JaccTokens {
return null; return null;
} }
StringBuilder stringbuffer = new StringBuilder(); StringBuilder stringbuffer = new StringBuilder();
do { while (true) {
stringbuffer.append(lexer.getLexeme()); stringbuffer.append(lexer.getLexeme());
if (lexer.nextToken() != 46) { if (lexer.nextToken() != 46) {
break; break;
@ -525,7 +518,7 @@ class JaccParser extends Phase implements JaccTokens {
break; break;
} }
stringbuffer.append('.'); stringbuffer.append('.');
} while (true); }
return stringbuffer.toString(); return stringbuffer.toString();
} }
@ -541,19 +534,20 @@ class JaccParser extends Phase implements JaccTokens {
case 4: // '\004' case 4: // '\004'
return literals.findOrAdd(s, lexer.getLastLiteral()); return literals.findOrAdd(s, lexer.getLastLiteral());
default:
break;
} }
return null; return null;
} }
private JaccSymbol parseNonterminal() { private JaccSymbol parseNonterminal() {
String s = lexer.getLexeme(); String s = lexer.getLexeme();
switch (lexer.getToken()) { if (lexer.getToken() == 3) {
case 3: // '\003' if (terminals.find(s) != null) {
if (terminals.find(s) != null) { return null;
return null; } else {
} else { return nonterms.findOrAdd(s);
return nonterms.findOrAdd(s); }
}
} }
return null; return null;
} }
@ -568,9 +562,10 @@ class JaccParser extends Phase implements JaccTokens {
jaccsymbol = nonterms.findOrAdd(s); jaccsymbol = nonterms.findOrAdd(s);
} }
return jaccsymbol; return jaccsymbol;
case 4: // '\004' case 4: // '\004'
return literals.findOrAdd(s, lexer.getLastLiteral()); return literals.findOrAdd(s, lexer.getLastLiteral());
default:
break;
} }
return null; return null;
} }
@ -584,6 +579,8 @@ class JaccParser extends Phase implements JaccTokens {
case 4: // '\004' case 4: // '\004'
return literals.find(lexer.getLastLiteral()); return literals.find(lexer.getLastLiteral());
default:
break;
} }
return null; return null;
} }
@ -598,7 +595,8 @@ class JaccParser extends Phase implements JaccTokens {
tail = symlist; tail = symlist;
} }
static int length(SymList symlist) { static int length(SymList list) {
SymList symlist = list;
int i = 0; int i = 0;
for (; symlist != null; symlist = symlist.tail) { for (; symlist != null; symlist = symlist.tail) {
i++; i++;
@ -606,9 +604,10 @@ class JaccParser extends Phase implements JaccTokens {
return i; return i;
} }
static JaccSymbol[] toArray(SymList symlist) { static JaccSymbol[] toArray(SymList list) {
SymList symlist = list;
int i = length(symlist); int i = length(symlist);
JaccSymbol ajaccsymbol[] = new JaccSymbol[i]; JaccSymbol[] ajaccsymbol = new JaccSymbol[i];
while (i > 0) { while (i > 0) {
ajaccsymbol[--i] = symlist.head; ajaccsymbol[--i] = symlist.head;
symlist = symlist.tail; symlist = symlist.tail;
@ -616,9 +615,10 @@ class JaccParser extends Phase implements JaccTokens {
return ajaccsymbol; return ajaccsymbol;
} }
static int[] toIntArray(SymList symlist) { static int[] toIntArray(SymList list) {
SymList symlist = list;
int i = length(symlist); int i = length(symlist);
int ai[] = new int[i]; int[] ai = new int[i];
while (i > 0) { while (i > 0) {
ai[--i] = symlist.head.getTokenNo(); ai[--i] = symlist.head.getTokenNo();
symlist = symlist.tail; symlist = symlist.tail;

View file

@ -16,11 +16,12 @@ class JaccProd extends Grammar.Prod {
JaccProd(Fixity fixity, JaccSymbol[] jaccsymbol, Position position, String s, int i) { JaccProd(Fixity fixity, JaccSymbol[] jaccsymbol, Position position, String s, int i) {
super(new int[jaccsymbol.length], i); super(new int[jaccsymbol.length], i);
this.fixity = fixity; this.fixity = fixity;
prodSyms = jaccsymbol; this.prodSyms = jaccsymbol;
actPos = position; this.actPos = position;
action = s; this.action = s;
} }
@Override
public String getLabel() { public String getLabel() {
return Integer.toString(getSeqNo()); return Integer.toString(getSeqNo());
} }

View file

@ -7,12 +7,15 @@ import org.xbib.jacc.grammar.Resolver;
import org.xbib.jacc.grammar.Tables; import org.xbib.jacc.grammar.Tables;
import org.xbib.jacc.util.IntSet; import org.xbib.jacc.util.IntSet;
/**
*
*/
class JaccResolver implements Resolver { class JaccResolver implements Resolver {
private LookaheadMachine machine; private LookaheadMachine machine;
private int numSRConflicts; private int numSRConflicts;
private int numRRConflicts; private int numRRConflicts;
private Conflicts conflicts[]; private Conflicts[] conflicts;
JaccResolver(LookaheadMachine lookaheadmachine) { JaccResolver(LookaheadMachine lookaheadmachine) {
numSRConflicts = 0; numSRConflicts = 0;
@ -49,6 +52,8 @@ class JaccResolver implements Resolver {
return; return;
case 3: case 3:
return; return;
default:
break;
} }
} }
conflicts[i] = Conflicts.sr(tables.getArgAt(i)[j], k, symbol, conflicts[i]); conflicts[i] = Conflicts.sr(tables.getArgAt(i)[j], k, symbol, conflicts[i]);

View file

@ -9,12 +9,9 @@ import org.xbib.jacc.grammar.SLRMachine;
/** /**
* *
*/ */
class Settings { class JaccSettings {
private static final int LR0 = 0; private MachineType machineType;
private static final int SLR1 = 1;
private static final int LALR1 = 2;
private int machineType;
private String packageName; private String packageName;
private String className; private String className;
private String interfaceName; private String interfaceName;
@ -27,28 +24,26 @@ class Settings {
private StringBuilder preTextBuffer; private StringBuilder preTextBuffer;
private StringBuilder postTextBuffer; private StringBuilder postTextBuffer;
Settings() { JaccSettings() {
machineType = LALR1; this.machineType = MachineType.LALR1;
preTextBuffer = new StringBuilder(); this.preTextBuffer = new StringBuilder();
postTextBuffer = new StringBuilder(); this.postTextBuffer = new StringBuilder();
} }
public int getMachineType() { void setMachineType(MachineType machineType) {
return machineType; this.machineType = machineType;
}
void setMachineType(int i) {
machineType = i;
} }
LookaheadMachine makeMachine(Grammar grammar) { LookaheadMachine makeMachine(Grammar grammar) {
if (machineType == LR0) { switch (machineType) {
return new LR0Machine(grammar); case LR0:
} return new LR0Machine(grammar);
if (machineType == SLR1) { case SLR1:
return new SLRMachine(grammar); return new SLRMachine(grammar);
} else { case LALR1:
return new LALRMachine(grammar); return new LALRMachine(grammar);
default:
return null;
} }
} }

View file

@ -51,7 +51,7 @@ class JaccSymbol extends Grammar.Symbol {
jaccProds = new JaccProd[1]; jaccProds = new JaccProd[1];
} else { } else {
if (pused >= jaccProds.length) { if (pused >= jaccProds.length) {
JaccProd ajaccprod[] = new JaccProd[2 * jaccProds.length]; JaccProd[] ajaccprod = new JaccProd[2 * jaccProds.length];
System.arraycopy(jaccProds, 0, ajaccprod, 0, jaccProds.length); System.arraycopy(jaccProds, 0, ajaccprod, 0, jaccProds.length);
jaccProds = ajaccprod; jaccProds = ajaccprod;
@ -61,7 +61,7 @@ class JaccSymbol extends Grammar.Symbol {
} }
public JaccProd[] getProds() { public JaccProd[] getProds() {
JaccProd ajaccprod[] = new JaccProd[pused]; JaccProd[] ajaccprod = new JaccProd[pused];
for (int i = 0; i < pused; i++) { for (int i = 0; i < pused; i++) {
ajaccprod[i] = jaccProds[i]; ajaccprod[i] = jaccProds[i];
ajaccprod[i].fixup(); ajaccprod[i].fixup();

View file

@ -3,12 +3,14 @@ package org.xbib.jacc;
abstract class JaccSymbols { abstract class JaccSymbols {
Node root; Node root;
int size; int size;
JaccSymbols() { JaccSymbols() {
root = null; root = null;
size = 0; size = 0;
} }
private static int fill(JaccSymbol ajaccsymbol[], int i, Node node) { private static int fill(JaccSymbol[] ajaccsymbol, int pos, Node node) {
int i = pos;
if (node != null) { if (node != null) {
i = fill(ajaccsymbol, i, node.left); i = fill(ajaccsymbol, i, node.left);
ajaccsymbol[i++] = node.data; ajaccsymbol[i++] = node.data;
@ -21,11 +23,14 @@ abstract class JaccSymbols {
return size; return size;
} }
int fill(JaccSymbol ajaccsymbol[], int i) { int fill(JaccSymbol[] ajaccsymbol, int i) {
return fill(ajaccsymbol, i, root); return fill(ajaccsymbol, i, root);
} }
protected static class Node { /**
*
*/
static class Node {
Node left; Node left;
JaccSymbol data; JaccSymbol data;

View file

@ -19,8 +19,8 @@ class JaccTables extends Tables {
JaccTables(LookaheadMachine lookaheadmachine, Resolver resolver) { JaccTables(LookaheadMachine lookaheadmachine, Resolver resolver) {
super(lookaheadmachine, resolver); super(lookaheadmachine, resolver);
errors = null; this.errors = null;
numErrors = 0; this.numErrors = 0;
} }
int getNumErrors() { int getNumErrors() {
@ -50,8 +50,10 @@ class JaccTables extends Tables {
return i; return i;
} }
} }
String as[] = new String[numErrors != 0 ? 2 * numErrors : 1]; String[] as = new String[numErrors != 0 ? 2 * numErrors : 1];
System.arraycopy(errors, 0, as, 0, numErrors); if (errors != null) {
System.arraycopy(errors, 0, as, 0, numErrors);
}
errors = as; errors = as;
errors[numErrors] = s; errors[numErrors] = s;
return numErrors++; return numErrors++;
@ -132,7 +134,8 @@ class JaccTables extends Tables {
defaultRow[i] = findDefault(); defaultRow[i] = findDefault();
} }
private void heapify(int i) { private void heapify(int pos) {
int i = pos;
int j = i; int j = i;
int k = idx[j]; int k = idx[j];
do { do {

View file

@ -0,0 +1,7 @@
package org.xbib.jacc;
/**
*/
public enum MachineType {
LR0, SLR1, LALR1
}

View file

@ -10,7 +10,7 @@ import java.io.Writer;
/** /**
* *
*/ */
class ParserOutput extends Output { class ParserOutput extends AbstractOutput {
private int yyaccept; private int yyaccept;
private int yyabort; private int yyabort;
@ -33,29 +33,30 @@ class ParserOutput extends Output {
tables.analyzeRows(); tables.analyzeRows();
} }
@Override
public void write(Writer writer) throws IOException { public void write(Writer writer) throws IOException {
datestamp(writer); datestamp(writer);
String s = settings.getPackageName(); String s = jaccSettings.getPackageName();
if (s != null) { if (s != null) {
writer.write("package " + s + ";\n"); writer.write("package " + s + ";\n");
} }
if (settings.getPreText() != null) { if (jaccSettings.getPreText() != null) {
writer.write(settings.getPreText() + "\n"); writer.write(jaccSettings.getPreText() + "\n");
} }
yyaccept = 2 * numStates; yyaccept = 2 * numStates;
stackOverflow = 2 * numStates + 1; stackOverflow = 2 * numStates + 1;
yyabort = 2 * numStates + 2; yyabort = 2 * numStates + 2;
errorHandler = 2 * numStates + 3; errorHandler = 2 * numStates + 3;
userErrorHandler = 2 * numStates + 4; userErrorHandler = 2 * numStates + 4;
int ai[] = new int[numNTs]; int[] ai = new int[numNTs];
stNumSwitches = new int[numStates]; stNumSwitches = new int[numStates];
for (int i = 0; i < numStates; i++) { for (int i = 0; i < numStates; i++) {
int ai1[] = machine.getGotosAt(i); int[] ai1 = machine.getGotosAt(i);
for (int anAi1 : ai1) { for (int anAi1 : ai1) {
ai[machine.getEntry(anAi1)]++; ai[machine.getEntry(anAi1)]++;
} }
byte abyte0[] = tables.getActionAt(i); byte[] abyte0 = tables.getActionAt(i);
int ai4[] = tables.getArgAt(i); int[] ai4 = tables.getArgAt(i);
int l3 = tables.getDefaultRowAt(i); int l3 = tables.getDefaultRowAt(i);
stNumSwitches[i] = 0; stNumSwitches[i] = 0;
for (int j4 = 0; j4 < abyte0.length; j4++) { for (int j4 = 0; j4 < abyte0.length; j4++) {
@ -73,7 +74,7 @@ class ParserOutput extends Output {
ntGotoSrc[j] = new int[ai[j]]; ntGotoSrc[j] = new int[ai[j]];
} }
for (int k = 0; k < numStates; k++) { for (int k = 0; k < numStates; k++) {
int ai2[] = machine.getGotosAt(k); int[] ai2 = machine.getGotosAt(k);
for (int anAi2 : ai2) { for (int anAi2 : ai2) {
int j3 = machine.getEntry(anAi2); int j3 = machine.getEntry(anAi2);
ntGoto[j3][--ai[j3]] = anAi2; ntGoto[j3][--ai[j3]] = anAi2;
@ -101,12 +102,12 @@ class ParserOutput extends Output {
} }
errMsgs = tables.getNumErrors() > 0; errMsgs = tables.getNumErrors() > 0;
errTok = numNTs; errTok = numNTs;
while (errTok < numSyms && !grammar.getSymbol(errTok).getName().equals("error")) { while (errTok < numSyms && !"error".equals(grammar.getSymbol(errTok).getName())) {
errTok++; errTok++;
} }
if (errTok < numSyms) { if (errTok < numSyms) {
for (int i1 = 0; i1 < numStates && !errUsed; i1++) { for (int i1 = 0; i1 < numStates && !errUsed; i1++) {
int ai3[] = machine.getShiftsAt(i1); int[] ai3 = machine.getShiftsAt(i1);
for (int l2 = 0; l2 < ai3.length && !errUsed; l2++) { for (int l2 = 0; l2 < ai3.length && !errUsed; l2++) {
if (machine.getEntry(ai3[l2]) == errTok) { if (machine.getEntry(ai3[l2]) == errTok) {
errUsed = true; errUsed = true;
@ -114,12 +115,12 @@ class ParserOutput extends Output {
} }
} }
} }
writer.write("public class " + settings.getClassName()); writer.write("public class " + jaccSettings.getClassName());
if (settings.getExtendsName() != null) { if (jaccSettings.getExtendsName() != null) {
writer.write(" extends " + settings.getExtendsName()); writer.write(" extends " + jaccSettings.getExtendsName());
} }
if (settings.getImplementsNames() != null) { if (jaccSettings.getImplementsNames() != null) {
writer.write(" implements " + settings.getImplementsNames()); writer.write(" implements " + jaccSettings.getImplementsNames());
} }
writer.write(" {\n"); writer.write(" {\n");
indent(writer, 1, new String[]{ indent(writer, 1, new String[]{
@ -132,8 +133,8 @@ class ParserOutput extends Output {
if (errUsed) { if (errUsed) {
indent(writer, 1, "private int yyerrstatus = 3;"); indent(writer, 1, "private int yyerrstatus = 3;");
} }
indent(writer, 1, "private " + settings.getTypeName() + "[] yysv;"); indent(writer, 1, "private " + jaccSettings.getTypeName() + "[] yysv;");
indent(writer, 1, "private " + settings.getTypeName() + " yyrv;"); indent(writer, 1, "private " + jaccSettings.getTypeName() + " yyrv;");
writer.write("\n"); writer.write("\n");
defineParse(writer, 1); defineParse(writer, 1);
defineExpand(writer, 1); defineExpand(writer, 1);
@ -142,15 +143,15 @@ class ParserOutput extends Output {
defineState(writer, 1, j1); defineState(writer, 1, j1);
} }
for (int k1 = 0; k1 < numNTs; k1++) { for (int k1 = 0; k1 < numNTs; k1++) {
Grammar.Prod aprod[] = grammar.getProds(k1); Grammar.Prod[] aprod = grammar.getProds(k1);
for (Grammar.Prod anAprod : aprod) { for (Grammar.Prod anAprod : aprod) {
defineReduce(writer, 1, anAprod, k1); defineReduce(writer, 1, anAprod, k1);
} }
defineNonterminal(writer, 1, k1); defineNonterminal(writer, 1, k1);
} }
defineErrMsgs(writer); defineErrMsgs(writer);
if (settings.getPostText() != null) { if (jaccSettings.getPostText() != null) {
writer.write(settings.getPostText() + "\n"); writer.write(jaccSettings.getPostText() + "\n");
} }
writer.write("}\n"); writer.write("}\n");
} }
@ -176,7 +177,10 @@ class ParserOutput extends Output {
indent(writer, i, new String[]{ indent(writer, i, new String[]{
"protected void yyexpand() {", " int[] newyyst = new int[2*yyst.length];" "protected void yyexpand() {", " int[] newyyst = new int[2*yyst.length];"
}); });
indent(writer, i + 1, settings.getTypeName() + "[] newyysv = new " + settings.getTypeName() + "[2*yyst.length];"); indent(writer, i + 1, jaccSettings.getTypeName() +
"[] newyysv = new " +
jaccSettings.getTypeName() +
"[2*yyst.length];");
indent(writer, i, new String[]{ indent(writer, i, new String[]{
" for (int i=0; i<yyst.length; i++) {", " for (int i=0; i<yyst.length; i++) {",
" newyyst[i] = yyst[i];", " newyyst[i] = yyst[i];",
@ -198,7 +202,7 @@ class ParserOutput extends Output {
indent(writer, i, "}"); indent(writer, i, "}");
writer.write("\n"); writer.write("\n");
indent(writer, i, "public void yyclearin() {"); indent(writer, i, "public void yyclearin() {");
indent(writer, i + 1, "yytok = (" + settings.getNextToken()); indent(writer, i + 1, "yytok = (" + jaccSettings.getNextToken());
indent(writer, i + 1, " );"); indent(writer, i + 1, " );");
indent(writer, i, "}"); indent(writer, i, "}");
writer.write("\n"); writer.write("\n");
@ -216,8 +220,8 @@ class ParserOutput extends Output {
if (errMsgs) { if (errMsgs) {
indent(writer, i + 1, "yyerrno = (-1);"); indent(writer, i + 1, "yyerrno = (-1);");
} }
indent(writer, i + 1, "yysv = new " + settings.getTypeName() + "[yyss];"); indent(writer, i + 1, "yysv = new " + jaccSettings.getTypeName() + "[yyss];");
indent(writer, i + 1, "yytok = (" + settings.getGetToken()); indent(writer, i + 1, "yytok = (" + jaccSettings.getGetToken());
indent(writer, i + 1, " );"); indent(writer, i + 1, " );");
indent(writer, i, new String[]{ indent(writer, i, new String[]{
"loop:", " for (;;) {", " switch (yyn) {" "loop:", " for (;;) {", " switch (yyn) {"
@ -243,9 +247,9 @@ class ParserOutput extends Output {
indent(writer, i, "case " + j + ":"); indent(writer, i, "case " + j + ":");
indent(writer, i + 1, "yyst[yysp] = " + j + ";"); indent(writer, i + 1, "yyst[yysp] = " + j + ";");
if (grammar.isTerminal(machine.getEntry(j))) { if (grammar.isTerminal(machine.getEntry(j))) {
indent(writer, i + 1, "yysv[yysp] = (" + settings.getGetSemantic()); indent(writer, i + 1, "yysv[yysp] = (" + jaccSettings.getGetSemantic());
indent(writer, i + 1, " );"); indent(writer, i + 1, " );");
indent(writer, i + 1, "yytok = (" + settings.getNextToken()); indent(writer, i + 1, "yytok = (" + jaccSettings.getNextToken());
indent(writer, i + 1, " );"); indent(writer, i + 1, " );");
if (errUsed) { if (errUsed) {
indent(writer, i + 1, "yyerrstatus++;"); indent(writer, i + 1, "yyerrstatus++;");
@ -287,7 +291,7 @@ class ParserOutput extends Output {
int k = tables.getDefaultRowAt(j); int k = tables.getDefaultRowAt(j);
if (stNumSwitches[j] > 0) { if (stNumSwitches[j] > 0) {
indent(writer, i, "switch (yytok) {"); indent(writer, i, "switch (yytok) {");
int ai1[] = tables.indexAt(j); int[] ai1 = tables.indexAt(j);
int k1; int k1;
for (int l = 0; l < ai1.length; l = k1) { for (int l = 0; l < ai1.length; l = k1) {
int i1 = ai1[l]; int i1 = ai1[l];
@ -357,7 +361,7 @@ class ParserOutput extends Output {
} }
private void translateAction(Writer writer, JaccProd jaccprod, String s) throws IOException { private void translateAction(Writer writer, JaccProd jaccprod, String s) throws IOException {
int ai[] = jaccprod.getRhs(); int[] ai = jaccprod.getRhs();
int i = s.length(); int i = s.length();
for (int j = 0; j < i; j++) { for (int j = 0; j < i; j++) {
char c = s.charAt(j); char c = s.charAt(j);
@ -466,11 +470,11 @@ class ParserOutput extends Output {
indent(writer, i, "case " + userErrorHandler + " :"); indent(writer, i, "case " + userErrorHandler + " :");
indent(writer, i + 1, new String[]{ indent(writer, i + 1, new String[]{
"if (yyerrstatus==0) {", "if (yyerrstatus==0) {",
" if ((" + settings.getGetToken(), " if ((" + jaccSettings.getGetToken(),
" )==ENDINPUT) {", " )==ENDINPUT) {",
" return false;", " return false;",
" }", " }",
" " + settings.getNextToken(), " " + jaccSettings.getNextToken(),
" ;" " ;"
}); });
indent(writer, i + 2, "yyn = " + numStates + " + yyst[yysp-1];"); indent(writer, i + 2, "yyn = " + numStates + " + yyst[yysp-1];");

View file

@ -9,7 +9,7 @@ import java.io.Writer;
/** /**
* *
*/ */
class TextOutput extends Output { class TextOutput extends AbstractOutput {
private boolean wantFirst; private boolean wantFirst;
@ -20,6 +20,7 @@ class TextOutput extends Output {
tables.analyzeRows(); tables.analyzeRows();
} }
@Override
public void write(Writer writer) throws IOException { public void write(Writer writer) throws IOException {
datestamp(writer); datestamp(writer);
for (int i = 0; i < numStates; i++) { for (int i = 0; i < numStates; i++) {
@ -33,10 +34,10 @@ class TextOutput extends Output {
writer.write("\n"); writer.write("\n");
} }
writer.write("\n"); writer.write("\n");
byte abyte0[] = tables.getActionAt(i); byte[] abyte0 = tables.getActionAt(i);
int ai1[] = tables.getArgAt(i); int[] ai1 = tables.getArgAt(i);
int j1 = tables.getDefaultRowAt(i); int j1 = tables.getDefaultRowAt(i);
int ai2[] = tables.indexAt(i); int[] ai2 = tables.indexAt(i);
for (int k1 = 0; k1 < abyte0.length; k1++) { for (int k1 = 0; k1 < abyte0.length; k1++) {
int l1 = ai2[k1]; int l1 = ai2[k1];
if (j1 < 0 || abyte0[l1] != abyte0[j1] || ai1[l1] != ai1[j1]) { if (j1 < 0 || abyte0[l1] != abyte0[j1] || ai1[l1] != ai1[j1]) {
@ -54,7 +55,7 @@ class TextOutput extends Output {
writer.write(describeAction(i, abyte0[j1], ai1[j1]) + "\n"); writer.write(describeAction(i, abyte0[j1], ai1[j1]) + "\n");
} }
writer.write("\n"); writer.write("\n");
int ai3[] = machine.getGotosAt(i); int[] ai3 = machine.getGotosAt(i);
if (ai3.length <= 0) { if (ai3.length <= 0) {
continue; continue;
} }
@ -77,10 +78,10 @@ class TextOutput extends Output {
} }
if (tables.getProdUnused() > 0) { if (tables.getProdUnused() > 0) {
for (int j = 0; j < numNTs; j++) { for (int j = 0; j < numNTs; j++) {
boolean aflag[] = tables.getProdsUsedAt(j); boolean[] aflag = tables.getProdsUsedAt(j);
for (int l = 0; l < aflag.length; l++) { for (int l = 0; l < aflag.length; l++) {
if (!aflag[l]) { if (!aflag[l]) {
int ai[] = grammar.getProds(j)[l].getRhs(); int[] ai = grammar.getProds(j)[l].getRhs();
writer.write("Rule not reduced: "); writer.write("Rule not reduced: ");
writer.write(grammar.getNonterminal(j).getName()); writer.write(grammar.getNonterminal(j).getName());
writer.write(" : "); writer.write(" : ");

View file

@ -9,7 +9,7 @@ import java.io.Writer;
/** /**
* *
*/ */
class TokensOutput extends Output { class TokensOutput extends AbstractOutput {
TokensOutput(Handler handler, JaccJob jaccjob) { TokensOutput(Handler handler, JaccJob jaccjob) {
super(handler, jaccjob); super(handler, jaccjob);
@ -18,11 +18,11 @@ class TokensOutput extends Output {
@Override @Override
public void write(Writer writer) throws IOException { public void write(Writer writer) throws IOException {
datestamp(writer); datestamp(writer);
String s = settings.getPackageName(); String s = jaccSettings.getPackageName();
if (s != null) { if (s != null) {
writer.write("package " + s + ";\n\n"); writer.write("package " + s + ";\n\n");
} }
writer.write("interface " + settings.getInterfaceName() + " {\n"); writer.write("interface " + jaccSettings.getInterfaceName() + " {\n");
indent(writer, 1); indent(writer, 1);
writer.write("int ENDINPUT = 0;\n"); writer.write("int ENDINPUT = 0;\n");
for (int i = 0; i < numTs - 1; i++) { for (int i = 0; i < numTs - 1; i++) {

View file

@ -1,23 +1,32 @@
package org.xbib.jacc.compiler; package org.xbib.jacc.compiler;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* *
*/ */
public class ConsoleHandler extends Handler { public class ConsoleHandler extends Handler {
private static final Logger logger = Logger.getLogger(ConsoleHandler.class.getName());
@Override
protected void respondTo(Diagnostic diagnostic) { protected void respondTo(Diagnostic diagnostic) {
Position position = diagnostic.getPos(); Position position = diagnostic.getPos();
Level level;
StringBuilder sb = new StringBuilder();
if (diagnostic instanceof Warning) { if (diagnostic instanceof Warning) {
System.err.print("WARNING: "); level = Level.WARNING;
} else { } else {
System.err.print("ERROR: "); level = Level.SEVERE;
} }
if (position != null) { if (position != null) {
System.err.println(position.describe()); sb.append(position.describe());
} }
String s = diagnostic.getText(); String s = diagnostic.getText();
if (s != null) { if (s != null) {
System.err.println(s); sb.append(s);
} }
System.err.println(); logger.log(level, sb.toString());
} }
} }

View file

@ -5,16 +5,17 @@ package org.xbib.jacc.compiler;
*/ */
abstract class Diagnostic extends Exception { abstract class Diagnostic extends Exception {
private String text; private final String text;
private Position position; private final transient Position position;
Diagnostic(String s) { Diagnostic(String s) {
text = s; this.position = null;
this.text = s;
} }
Diagnostic(Position position, String s) { Diagnostic(Position position, String s) {
this.position = position; this.position = position;
text = s; this.text = s;
} }
String getText() { String getText() {

View file

@ -8,30 +8,24 @@ import java.io.Reader;
*/ */
public class JavaSource extends Source { public class JavaSource extends Source {
private final StringBuilder buf; private final StringBuilder sb;
private Reader input; private Reader input;
private int tabwidth; private int tabwidth;
private String description;
private int c0; private int c0;
private int c1; private int c1;
private int lineNumber; private int lineNumber;
public JavaSource(Handler handler, String s, Reader reader) { public JavaSource(Handler handler, Reader reader) {
this(handler, s, reader, 8); this(handler, reader, 8);
} }
private JavaSource(Handler handler, String s, Reader reader, int i) { private JavaSource(Handler handler, Reader reader, int i) {
super(handler); super(handler);
c1 = 0; this.c1 = 0;
lineNumber = 0; this.lineNumber = 0;
description = s; this.input = reader;
input = reader; this.tabwidth = i;
tabwidth = i; this.sb = new StringBuilder();
buf = new StringBuilder();
}
public String describe() {
return description;
} }
private void skip() throws IOException { private void skip() throws IOException {
@ -49,7 +43,7 @@ public class JavaSource extends Source {
if (input == null) { if (input == null) {
return null; return null;
} }
buf.setLength(0); sb.setLength(0);
if (lineNumber++ == 0) { if (lineNumber++ == 0) {
skip(); skip();
skip(); skip();
@ -77,24 +71,24 @@ public class JavaSource extends Source {
if (k != 4) { if (k != 4) {
report(new Warning("Error in Unicode escape sequence")); report(new Warning("Error in Unicode escape sequence"));
} else { } else {
buf.append((char) i); sb.append((char) i);
} }
continue; continue;
} }
buf.append('\\'); sb.append('\\');
if (c0 == -1) { if (c0 == -1) {
break; break;
} }
buf.append((char) c0); sb.append((char) c0);
skip(); skip();
} else if (c0 == 9 && tabwidth > 0) { } else if (c0 == 9 && tabwidth > 0) {
for (int j = tabwidth - buf.length() % tabwidth; j > 0; j--) { for (int j = tabwidth - sb.length() % tabwidth; j > 0; j--) {
buf.append(' '); sb.append(' ');
} }
skip(); skip();
} else { } else {
buf.append((char) c0); sb.append((char) c0);
skip(); skip();
} }
} while (true); } while (true);
@ -104,18 +98,20 @@ public class JavaSource extends Source {
if (c0 == 10) { if (c0 == 10) {
skip(); skip();
} }
return buf.toString(); return sb.toString();
} }
@Override
public int getLineNo() { public int getLineNo() {
return lineNumber; return lineNumber;
} }
@Override
public void close() throws IOException { public void close() throws IOException {
if (input != null) { if (input != null) {
input.close(); input.close();
input = null; input = null;
buf.setLength(0); sb.setLength(0);
} }
} }
} }

View file

@ -3,9 +3,9 @@ package org.xbib.jacc.compiler;
/** /**
* *
*/ */
public abstract class Position { public interface Position {
public abstract String describe(); String describe();
public abstract Position copy(); Position copy();
} }

View file

@ -1,18 +1,17 @@
package org.xbib.jacc.compiler; package org.xbib.jacc.compiler;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
/** /**
* *
*/ */
public abstract class Source extends Phase { public abstract class Source extends Phase implements Closeable {
Source(Handler handler) { Source(Handler handler) {
super(handler); super(handler);
} }
public abstract String describe();
public abstract String readLine() throws IOException; public abstract String readLine() throws IOException;
public abstract int getLineNo(); public abstract int getLineNo();
@ -21,6 +20,4 @@ public abstract class Source extends Phase {
return null; return null;
} }
public void close() throws IOException {
}
} }

View file

@ -15,13 +15,14 @@ public abstract class SourceLexer extends Lexer {
public SourceLexer(Handler handler, Source source) throws IOException { public SourceLexer(Handler handler, Source source) throws IOException {
super(handler); super(handler);
col = -1; this.col = -1;
this.source = source; this.source = source;
pos = new SourcePosition(source); this.pos = new SourcePosition(source);
line = source.readLine(); this.line = source.readLine();
nextChar(); nextChar();
} }
@Override
public Position getPos() { public Position getPos() {
return pos.copy(); return pos.copy();
} }
@ -50,6 +51,7 @@ public abstract class SourceLexer extends Lexer {
return c; return c;
} }
@Override
public void close() throws IOException { public void close() throws IOException {
if (source != null) { if (source != null) {
source.close(); source.close();

View file

@ -3,7 +3,7 @@ package org.xbib.jacc.compiler;
/** /**
* *
*/ */
class SourcePosition extends Position { class SourcePosition implements Position {
private final Source source; private final Source source;
@ -30,9 +30,6 @@ class SourcePosition extends Position {
public String describe() { public String describe() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (source != null) { if (source != null) {
sb.append('"');
sb.append(source.describe());
sb.append('"');
if (row > 0) { if (row > 0) {
sb.append(", "); sb.append(", ");
} }

View file

@ -1,5 +1,8 @@
package org.xbib.jacc.grammar; package org.xbib.jacc.grammar;
import java.io.IOException;
import java.io.Writer;
/** /**
* *
*/ */
@ -23,7 +26,7 @@ abstract class Analysis {
} }
} }
private void analyzeComponent(int ai[]) { private void analyzeComponent(int[] ai) {
for (boolean flag = true; flag; ) { for (boolean flag = true; flag; ) {
flag = false; flag = false;
int i = 0; int i = 0;
@ -34,5 +37,21 @@ abstract class Analysis {
} }
} }
public void display(Writer writer, int numNTs, Grammar grammar) throws IOException {
int i = 0;
for (int j = 0; j < numNTs; j++) {
if (!isAt(j)) {
continue;
}
if (i > 0) {
writer.write(", ");
}
writer.write(grammar.getSymbol(j).getName());
i++;
}
}
public abstract boolean isAt(int i);
protected abstract boolean analyze(int i); protected abstract boolean analyze(int i);
} }

View file

@ -8,38 +8,39 @@ import java.io.Writer;
*/ */
public final class Finitary extends Analysis { public final class Finitary extends Analysis {
private boolean[] finitary; private final boolean[] finitaries;
private boolean[] consider; private final boolean[] consider;
private Grammar grammar; private final Grammar grammar;
private int numNTs; private final int numNTs;
Finitary(Grammar grammar) { Finitary(Grammar grammar) {
super(grammar.getComponents()); super(grammar.getComponents());
this.grammar = grammar; this.grammar = grammar;
numNTs = grammar.getNumNTs(); numNTs = grammar.getNumNTs();
finitary = new boolean[numNTs]; finitaries = new boolean[numNTs];
consider = new boolean[numNTs]; consider = new boolean[numNTs];
for (int i = 0; i < numNTs; i++) { for (int i = 0; i < numNTs; i++) {
finitary[i] = false; finitaries[i] = false;
consider[i] = true; consider[i] = true;
} }
bottomUp(); bottomUp();
} }
@Override
protected boolean analyze(int i) { protected boolean analyze(int i) {
boolean flag = false; boolean flag = false;
if (consider[i]) { if (consider[i]) {
int j = 0; int j = 0;
Grammar.Prod[] aprod = grammar.getProds(i); Grammar.Prod[] prods = grammar.getProds(i);
for (Grammar.Prod anAprod : aprod) { for (Grammar.Prod prod : prods) {
int ai[] = anAprod.getRhs(); int[] ai = prod.getRhs();
int l; int l;
l = 0; l = 0;
while (l < ai.length && at(ai[l])) { while (l < ai.length && isAt(ai[l])) {
l++; l++;
} }
if (l >= ai.length) { if (l >= ai.length) {
finitary[i] = true; finitaries[i] = true;
consider[i] = false; consider[i] = false;
flag = true; flag = true;
break; break;
@ -48,30 +49,20 @@ public final class Finitary extends Analysis {
j++; j++;
} }
} }
if (j == aprod.length) { if (j == prods.length) {
consider[i] = false; consider[i] = false;
} }
} }
return flag; return flag;
} }
public boolean at(int i) { public boolean isAt(int i) {
return grammar.isTerminal(i) || finitary[i]; return grammar.isTerminal(i) || finitaries[i];
} }
public void display(Writer writer) throws IOException { public void display(Writer writer) throws IOException {
writer.write("Finitary = {"); writer.write("Finitary = {");
int i = 0; super.display(writer, numNTs, grammar);
for (int j = 0; j < numNTs; j++) {
if (!at(j)) {
continue;
}
if (i > 0) {
writer.write(", ");
}
writer.write(grammar.getSymbol(j).getName());
i++;
}
writer.write("}\n"); writer.write("}\n");
} }
} }

View file

@ -13,7 +13,7 @@ public class First extends Analysis {
private Grammar grammar; private Grammar grammar;
private Nullable nullable; private Nullable nullable;
private int numNTs; private int numNTs;
private int[][] first; private int[][] firsts;
First(Grammar grammar1, Nullable nullable1) { First(Grammar grammar1, Nullable nullable1) {
super(grammar1.getComponents()); super(grammar1.getComponents());
@ -21,13 +21,19 @@ public class First extends Analysis {
nullable = nullable1; nullable = nullable1;
numNTs = grammar1.getNumNTs(); numNTs = grammar1.getNumNTs();
int numTs = grammar1.getNumTs(); int numTs = grammar1.getNumTs();
first = new int[numNTs][]; firsts = new int[numNTs][];
for (int i = 0; i < numNTs; i++) { for (int i = 0; i < numNTs; i++) {
first[i] = BitSet.make(numTs); firsts[i] = BitSet.make(numTs);
} }
bottomUp(); bottomUp();
} }
@Override
public boolean isAt(int i) {
return false;
}
@Override
protected boolean analyze(int i) { protected boolean analyze(int i) {
boolean flag = false; boolean flag = false;
Grammar.Prod[] aprod = grammar.getProds(i); Grammar.Prod[] aprod = grammar.getProds(i);
@ -40,15 +46,15 @@ public class First extends Analysis {
continue label0; continue label0;
} }
if (grammar.isTerminal(ai[k])) { if (grammar.isTerminal(ai[k])) {
if (BitSet.addTo(first[i], ai[k] - numNTs)) { if (BitSet.addTo(firsts[i], ai[k] - numNTs)) {
flag = true; flag = true;
} }
continue label0; continue label0;
} }
if (BitSet.addTo(first[i], first[ai[k]])) { if (BitSet.addTo(firsts[i], firsts[ai[k]])) {
flag = true; flag = true;
} }
if (!nullable.at(ai[k])) { if (!nullable.isAt(ai[k])) {
continue label0; continue label0;
} }
k++; k++;
@ -59,12 +65,12 @@ public class First extends Analysis {
} }
public int[] at(int i) { public int[] at(int i) {
return first[i]; return firsts[i];
} }
public void display(Writer writer) throws IOException { public void display(Writer writer) throws IOException {
writer.write("First sets:\n"); writer.write("First sets:\n");
for (int i = 0; i < first.length; i++) { for (int i = 0; i < firsts.length; i++) {
writer.write(" First(" + grammar.getSymbol(i) + "): {"); writer.write(" First(" + grammar.getSymbol(i) + "): {");
writer.write(grammar.displaySymbolSet(at(i), numNTs)); writer.write(grammar.displaySymbolSet(at(i), numNTs));
writer.write("}\n"); writer.write("}\n");

View file

@ -14,7 +14,7 @@ public class Follow extends Analysis {
private Nullable nullable; private Nullable nullable;
private First first; private First first;
private int numNTs; private int numNTs;
private int[][] follow; private int[][] follows;
Follow(Grammar grammar, Nullable nullable, First first1) { Follow(Grammar grammar, Nullable nullable, First first1) {
super(grammar.getComponents()); super(grammar.getComponents());
@ -23,17 +23,23 @@ public class Follow extends Analysis {
first = first1; first = first1;
numNTs = grammar.getNumNTs(); numNTs = grammar.getNumNTs();
int numTs = grammar.getNumTs(); int numTs = grammar.getNumTs();
follow = new int[numNTs][]; follows = new int[numNTs][];
for (int i = 0; i < numNTs; i++) { for (int i = 0; i < numNTs; i++) {
follow[i] = BitSet.make(numTs); follows[i] = BitSet.make(numTs);
} }
BitSet.set(follow[0], numTs - 1); BitSet.set(follows[0], numTs - 1);
topDown(); topDown();
} }
@Override
public boolean isAt(int i) {
return false;
}
@Override
protected boolean analyze(int i) { protected boolean analyze(int i) {
boolean flag = false; boolean flag = false;
Grammar.Prod aprod[] = grammar.getProds(i); Grammar.Prod[] aprod = grammar.getProds(i);
for (Grammar.Prod anAprod : aprod) { for (Grammar.Prod anAprod : aprod) {
int[] ai = anAprod.getRhs(); int[] ai = anAprod.getRhs();
for (int k = 0; k < ai.length; k++) { for (int k = 0; k < ai.length; k++) {
@ -46,20 +52,20 @@ public class Follow extends Analysis {
break; break;
} }
if (grammar.isTerminal(ai[l])) { if (grammar.isTerminal(ai[l])) {
if (BitSet.addTo(follow[ai[k]], ai[l] - numNTs)) { if (BitSet.addTo(follows[ai[k]], ai[l] - numNTs)) {
flag = true; flag = true;
} }
break; break;
} }
if (BitSet.addTo(follow[ai[k]], first.at(ai[l]))) { if (BitSet.addTo(follows[ai[k]], first.at(ai[l]))) {
flag = true; flag = true;
} }
if (!nullable.at(ai[l])) { if (!nullable.isAt(ai[l])) {
break; break;
} }
l++; l++;
} while (true); } while (true);
if (l >= ai.length && BitSet.addTo(follow[ai[k]], follow[i])) { if (l >= ai.length && BitSet.addTo(follows[ai[k]], follows[i])) {
flag = true; flag = true;
} }
} }
@ -68,12 +74,12 @@ public class Follow extends Analysis {
} }
public int[] at(int i) { public int[] at(int i) {
return follow[i]; return follows[i];
} }
public void display(Writer writer) throws IOException { public void display(Writer writer) throws IOException {
writer.write("Follow sets:\n"); writer.write("Follow sets:\n");
for (int i = 0; i < follow.length; i++) { for (int i = 0; i < follows.length; i++) {
writer.write(" Follow(" + grammar.getSymbol(i) + "): {"); writer.write(" Follow(" + grammar.getSymbol(i) + "): {");
writer.write(grammar.displaySymbolSet(at(i), numNTs)); writer.write(grammar.displaySymbolSet(at(i), numNTs));
writer.write("}\n"); writer.write("}\n");

View file

@ -1,5 +1,6 @@
package org.xbib.jacc.grammar; package org.xbib.jacc.grammar;
import org.xbib.jacc.JaccException;
import org.xbib.jacc.util.BitSet; import org.xbib.jacc.util.BitSet;
import org.xbib.jacc.util.Interator; import org.xbib.jacc.util.Interator;
import org.xbib.jacc.util.SCC; import org.xbib.jacc.util.SCC;
@ -25,7 +26,7 @@ public class Grammar {
private First first; private First first;
private Follow follow; private Follow follow;
public Grammar(Symbol[] symbols, Prod[][] prods) throws Exception { public Grammar(Symbol[] symbols, Prod[][] prods) throws JaccException {
validate(symbols, prods); validate(symbols, prods);
this.symbols = symbols; this.symbols = symbols;
numSyms = symbols.length; numSyms = symbols.length;
@ -36,37 +37,37 @@ public class Grammar {
comps = SCC.get(depends, revdeps, numNTs); comps = SCC.get(depends, revdeps, numNTs);
} }
private static void validate(Symbol[] symbol, Prod[][] prod) throws Exception { private static void validate(Symbol[] symbol, Prod[][] prod) throws JaccException {
if (symbol == null || symbol.length == 0) { if (symbol == null || symbol.length == 0) {
throw new Exception("No symbols specified"); throw new JaccException("No symbols specified");
} }
for (int i = 0; i < symbol.length; i++) { for (int i = 0; i < symbol.length; i++) {
if (symbol[i] == null) { if (symbol[i] == null) {
throw new Exception("Symbol " + i + " is null"); throw new JaccException("Symbol " + i + " is null");
} }
} }
int j = symbol.length; int j = symbol.length;
if (prod == null || prod.length == 0) { if (prod == null || prod.length == 0) {
throw new Exception("No nonterminals specified"); throw new JaccException("No nonterminals specified");
} }
if (prod.length > j) { if (prod.length > j) {
throw new Exception("To many nonterminals specified"); throw new JaccException("To many nonterminals specified");
} }
if (prod.length == j) { if (prod.length == j) {
throw new Exception("No terminals specified"); throw new JaccException("No terminals specified");
} }
for (int k = 0; k < prod.length; k++) { for (int k = 0; k < prod.length; k++) {
if (prod[k] == null || prod[k].length == 0) { if (prod[k] == null || prod[k].length == 0) {
throw new Exception("Nonterminal " + symbol[k] + " (number " + k + ") has no productions"); throw new JaccException("Nonterminal " + symbol[k] + " (number " + k + ") has no productions");
} }
for (int l = 0; l < prod[k].length; l++) { for (int l = 0; l < prod[k].length; l++) {
int[] ai = prod[k][l].getRhs(); int[] ai = prod[k][l].getRhs();
if (ai == null) { if (ai == null) {
throw new Exception("Production " + l + " for symbol " + symbol[k] + " (number " + k + ") is null"); throw new JaccException("Production " + l + " for symbol " + symbol[k] + " (number " + k + ") is null");
} }
for (int m : ai) { for (int m : ai) {
if (m < 0 || m >= j - 1) { if (m < 0 || m >= j - 1) {
throw new Exception("Out of range symbol " + m + " in production " + l + " for symbol " + throw new JaccException("Out of range symbol " + m + " in production " + l + " for symbol " +
symbol[k] + " (number " + k + ")"); symbol[k] + " (number " + k + ")");
} }
} }
@ -227,7 +228,7 @@ public class Grammar {
int j = 0; int j = 0;
for (Interator interator = BitSet.interator(ai, i); interator.hasNext(); for (Interator interator = BitSet.interator(ai, i); interator.hasNext();
sb.append(symbols[interator.next()].getName())) { sb.append(symbols[interator.next()].getName())) {
if (j++ != 0) { if (j++ > 0) {
sb.append(", "); sb.append(", ");
} }
} }
@ -239,7 +240,7 @@ public class Grammar {
*/ */
public static class Prod { public static class Prod {
int[] rhs; private int[] rhs;
private int seqNo; private int seqNo;
public Prod(int[] ai, int i) { public Prod(int[] ai, int i) {

View file

@ -12,9 +12,9 @@ import java.io.Writer;
*/ */
public class LALRMachine extends LookaheadMachine { public class LALRMachine extends LookaheadMachine {
private Nullable nullable; private final Nullable nullable;
private First first; private final First first;
private int[][] predState; private final int[][] predState;
private int numGotos; private int numGotos;
private int[] stateFirstGoto; private int[] stateFirstGoto;
private int[] gotoSource; private int[] gotoSource;
@ -25,13 +25,14 @@ public class LALRMachine extends LookaheadMachine {
public LALRMachine(Grammar grammar) { public LALRMachine(Grammar grammar) {
super(grammar); super(grammar);
nullable = grammar.getNullable(); this.nullable = grammar.getNullable();
first = grammar.getFirst(); this.first = grammar.getFirst();
predState = SCC.invert(succState, numStates); this.predState = SCC.invert(succState, numStates);
calcGotoLA(); calcGotoLA();
calcLookahead(); calcLookahead();
} }
@Override
public int[] getLookaheadAt(int i, int j) { public int[] getLookaheadAt(int i, int j) {
return laReds[i][j]; return laReds[i][j];
} }
@ -104,7 +105,8 @@ public class LALRMachine extends LookaheadMachine {
gotoTargets[i] = intset1.toArray(); gotoTargets[i] = intset1.toArray();
} }
private LR0Items.Item calcFirsts(int[] ai, LR0Items.Item item) { private LR0Items.Item calcFirsts(int[] ai, LR0Items.Item it) {
LR0Items.Item item = it;
do { do {
if (!item.canGoto()) { if (!item.canGoto()) {
break; break;
@ -115,7 +117,7 @@ public class LALRMachine extends LookaheadMachine {
break; break;
} }
BitSet.union(ai, first.at(i)); BitSet.union(ai, first.at(i));
if (!nullable.at(i)) { if (!nullable.isAt(i)) {
break; break;
} }
item = items.getItem(item.getNextItem()); item = items.getItem(item.getNextItem());
@ -126,7 +128,8 @@ public class LALRMachine extends LookaheadMachine {
return item; return item;
} }
private void findTargets(IntSet intset, int i, int j, int[] ai, int k) { private void findTargets(IntSet intset, int i, int j, int[] ai, int kk) {
int k = kk;
if (k == 0) { if (k == 0) {
int[] ai1 = getGotosAt(i); int[] ai1 = getGotosAt(i);
int i1 = 0; int i1 = 0;
@ -164,7 +167,8 @@ public class LALRMachine extends LookaheadMachine {
} }
} }
private void lookBack(int[] ai, int i, int j, int[] ai1, int k) { private void lookBack(int[] ai, int i, int j, int[] ai1, int kk) {
int k = kk;
if (k == 0) { if (k == 0) {
int[] ai2 = getGotosAt(i); int[] ai2 = getGotosAt(i);
for (int i1 = 0; i1 < ai2.length; i1++) { for (int i1 = 0; i1 < ai2.length; i1++) {

View file

@ -25,6 +25,11 @@ final class Left extends Analysis {
bottomUp(); bottomUp();
} }
@Override
public boolean isAt(int i) {
return false;
}
protected boolean analyze(int i) { protected boolean analyze(int i) {
boolean flag = false; boolean flag = false;
Grammar.Prod aprod[] = grammar.getProds(i); Grammar.Prod aprod[] = grammar.getProds(i);

View file

@ -127,12 +127,14 @@ public class Machine {
} }
int[] ai1 = new int[i]; int[] ai1 = new int[i];
int j1 = 0; int j1 = 0;
for (int l1 = 0; j1 < i; l1++) { int l1 = 0;
while (j1 < i) {
if (aintset[l1] != null) { if (aintset[l1] != null) {
ai1[j1] = addState(l1, aintset[l1]); ai1[j1] = addState(l1, aintset[l1]);
aintset[l1] = null; aintset[l1] = null;
j1++; j1++;
} }
l1++;
} }
i = 0; i = 0;
succState[j] = ai1; succState[j] = ai1;

View file

@ -8,38 +8,39 @@ import java.io.Writer;
*/ */
public class Nullable extends Analysis { public class Nullable extends Analysis {
private boolean nullable[]; private final boolean[] nullables;
private boolean consider[]; private final boolean[] consider;
private Grammar grammar; private final Grammar grammar;
private int numNTs; private final int numNTs;
Nullable(Grammar grammar) { Nullable(Grammar grammar) {
super(grammar.getComponents()); super(grammar.getComponents());
this.grammar = grammar; this.grammar = grammar;
numNTs = grammar.getNumNTs(); numNTs = grammar.getNumNTs();
nullable = new boolean[numNTs]; nullables = new boolean[numNTs];
consider = new boolean[numNTs]; consider = new boolean[numNTs];
for (int i = 0; i < numNTs; i++) { for (int i = 0; i < numNTs; i++) {
nullable[i] = false; nullables[i] = false;
consider[i] = true; consider[i] = true;
} }
bottomUp(); bottomUp();
} }
@Override
protected boolean analyze(int i) { protected boolean analyze(int i) {
boolean flag = false; boolean flag = false;
if (consider[i]) { if (consider[i]) {
int j = 0; int j = 0;
Grammar.Prod aprod[] = grammar.getProds(i); Grammar.Prod[] prods = grammar.getProds(i);
for (Grammar.Prod anAprod : aprod) { for (Grammar.Prod prod : prods) {
int ai[] = anAprod.getRhs(); int[] ai = prod.getRhs();
int l; int l;
l = 0; l = 0;
while (l < ai.length && at(ai[l])) { while (l < ai.length && isAt(ai[l])) {
l++; l++;
} }
if (l >= ai.length) { if (l >= ai.length) {
nullable[i] = true; nullables[i] = true;
consider[i] = false; consider[i] = false;
flag = true; flag = true;
break; break;
@ -48,30 +49,21 @@ public class Nullable extends Analysis {
j++; j++;
} }
} }
if (j == aprod.length) { if (j == prods.length) {
consider[i] = false; consider[i] = false;
} }
} }
return flag; return flag;
} }
public boolean at(int i) { @Override
return grammar.isNonterminal(i) && nullable[i]; public boolean isAt(int i) {
return grammar.isNonterminal(i) && nullables[i];
} }
public void display(Writer writer) throws IOException { public void display(Writer writer) throws IOException {
writer.write("Nullable = {"); writer.write("Nullable = {");
int i = 0; super.display(writer, numNTs, grammar);
for (int j = 0; j < numNTs; j++) {
if (!at(j)) {
continue;
}
if (i > 0) {
writer.write(", ");
}
writer.write(grammar.getSymbol(j).getName());
i++;
}
writer.write("}\n"); writer.write("}\n");
} }
} }

View file

@ -14,7 +14,7 @@ public class Parser {
private static final int GOTO = 3; private static final int GOTO = 3;
private static final int REDUCE = 4; private static final int REDUCE = 4;
private Tables tables; private Tables tables;
private int input[]; private int[] input;
private Machine machine; private Machine machine;
private Grammar grammar; private Grammar grammar;
private int position; private int position;
@ -23,16 +23,16 @@ public class Parser {
private Stack stack; private Stack stack;
private int state; private int state;
public Parser(Tables tables, int ai[]) { public Parser(Tables tables, int[] ai) {
position = 0; this.position = 0;
currSymbol = -1; this.currSymbol = -1;
reducedNT = -1; this.reducedNT = -1;
stack = new Stack(); this.stack = new Stack();
state = ACCEPT; this.state = ACCEPT;
this.tables = tables; this.tables = tables;
input = ai; this.input = ai;
machine = tables.getMachine(); this.machine = tables.getMachine();
grammar = machine.getGrammar(); this.grammar = machine.getGrammar();
} }
public int getState() { public int getState() {
@ -84,6 +84,8 @@ public class Parser {
case 2: case 2:
reduce(ai[i]); reduce(ai[i]);
return REDUCE; return REDUCE;
default:
break;
} }
return ERROR; return ERROR;
} }
@ -106,7 +108,7 @@ public class Parser {
} }
private boolean gotoState(int i) { private boolean gotoState(int i) {
int ai[] = machine.getGotosAt(state); int[] ai = machine.getGotosAt(state);
for (int anAi : ai) { for (int anAi : ai) {
if (i == machine.getEntry(anAi)) { if (i == machine.getEntry(anAi)) {
state = anAi; state = anAi;
@ -122,18 +124,21 @@ public class Parser {
writer.write(state); writer.write(state);
writer.write(" "); writer.write(" ");
} }
writer.write("_ "); writer.write("_");
if (reducedNT >= 0) { if (reducedNT >= 0) {
writer.write(" ");
writer.write(grammar.getSymbol(reducedNT).toString()); writer.write(grammar.getSymbol(reducedNT).toString());
writer.write(" "); writer.write(" ");
} }
if (currSymbol >= 0) { if (currSymbol >= 0) {
writer.write(" ");
writer.write(grammar.getSymbol(currSymbol).toString()); writer.write(grammar.getSymbol(currSymbol).toString());
if (position < input.length) { if (position < input.length) {
writer.write(" ..."); writer.write(" ...");
} }
} else { } else {
if (position < input.length) { if (position < input.length) {
writer.write(" ");
writer.write(grammar.getSymbol(input[position]).toString()); writer.write(grammar.getSymbol(input[position]).toString());
writer.write(" ..."); writer.write(" ...");
} }

View file

@ -19,6 +19,7 @@ public class SLRMachine extends LookaheadMachine {
calcLookahead(); calcLookahead();
} }
@Override
public int[] getLookaheadAt(int i, int j) { public int[] getLookaheadAt(int i, int j) {
return laReds[i][j]; return laReds[i][j];
} }
@ -36,6 +37,7 @@ public class SLRMachine extends LookaheadMachine {
} }
} }
@Override
public void display(Writer writer) throws IOException { public void display(Writer writer) throws IOException {
super.display(writer); super.display(writer);
for (int i = 0; i < numStates; i++) { for (int i = 0; i < numStates; i++) {

View file

@ -37,7 +37,7 @@ public class BitSet {
public static boolean addTo(int[] ai, int[] ai1) { public static boolean addTo(int[] ai, int[] ai1) {
if (ai.length < ai1.length) { if (ai.length < ai1.length) {
throw new Error("bitset arguments do not match"); throw new IllegalArgumentException("bitset arguments do not match");
} }
int i = 0; int i = 0;
boolean flag = false; boolean flag = false;
@ -125,45 +125,4 @@ public class BitSet {
public static Interator interator(int[] ai, int i) { public static Interator interator(int[] ai, int i) {
return new BitSetInterator(ai, i); return new BitSetInterator(ai, i);
} }
private static class BitSetInterator extends Interator {
int[] set;
int pos;
int mask;
int num;
int bitCount;
BitSetInterator(int[] ai, int i) {
set = ai;
num = i;
pos = 0;
mask = 1;
bitCount = 0;
}
private void advance() {
num++;
if (++bitCount == 32) {
pos++;
bitCount = 0;
mask = 1;
} else {
mask <<= 1;
}
}
public int next() {
int i = num;
advance();
return i;
}
public boolean hasNext() {
while (pos < set.length && (set[pos] & mask) == 0) {
advance();
}
return pos < set.length;
}
}
} }

View file

@ -0,0 +1,44 @@
package org.xbib.jacc.util;
class BitSetInterator implements Interator {
private int[] set;
private int pos;
private int mask;
private int num;
private int bitCount;
BitSetInterator(int[] ai, int i) {
this.set = ai;
this.num = i;
this.pos = 0;
this.mask = 1;
this.bitCount = 0;
}
private void advance() {
num++;
if (++bitCount == 32) {
pos++;
bitCount = 0;
mask = 1;
} else {
mask <<= 1;
}
}
@Override
public int next() {
int i = num;
advance();
return i;
}
@Override
public boolean hasNext() {
while (pos < set.length && (set[pos] & mask) == 0) {
advance();
}
return pos < set.length;
}
}

View file

@ -3,7 +3,7 @@ package org.xbib.jacc.util;
/** /**
* *
*/ */
class ElemInterator extends Interator { class ElemInterator implements Interator {
private int count; private int count;
private int limit; private int limit;
@ -19,10 +19,12 @@ class ElemInterator extends Interator {
this(ai, 0, ai.length); this(ai, 0, ai.length);
} }
@Override
public int next() { public int next() {
return a[count++]; return a[count++];
} }
@Override
public boolean hasNext() { public boolean hasNext() {
return count < limit; return count < limit;
} }

View file

@ -115,11 +115,13 @@ public class IntSet {
public void display(Writer writer) throws IOException { public void display(Writer writer) throws IOException {
Interator interator1 = interator(); Interator interator1 = interator();
writer.write("{"); writer.write("{");
for (int i = 0; interator1.hasNext(); i++) { int i = 0;
while (interator1.hasNext()) {
if (i != 0) { if (i != 0) {
writer.write(", "); writer.write(", ");
} }
writer.write(interator1.next()); writer.write(interator1.next());
i++;
} }
writer.write("}"); writer.write("}");
writer.write(": used = " + used + ", length = " + elems.length + "\n"); writer.write(": used = " + used + ", length = " + elems.length + "\n");

View file

@ -3,9 +3,9 @@ package org.xbib.jacc.util;
/** /**
* *
*/ */
public abstract class Interator { public interface Interator {
public abstract int next(); int next();
public abstract boolean hasNext(); boolean hasNext();
} }

View file

@ -49,10 +49,12 @@ public class SCC {
compNo = new int[i]; compNo = new int[i];
} }
@Override
void doneVisit(int i) { void doneVisit(int i) {
compNo[i] = numComps; compNo[i] = numComps;
} }
@Override
void doneTree() { void doneTree() {
numComps++; numComps++;
} }
@ -76,6 +78,7 @@ public class SCC {
} }
private static class ArrangeByFinish extends DepthFirst { private static class ArrangeByFinish extends DepthFirst {
private int dfsNum; private int dfsNum;
private int[] order; private int[] order;
@ -85,10 +88,16 @@ public class SCC {
order = new int[dfsNum]; order = new int[dfsNum];
} }
@Override
void doneVisit(int i) { void doneVisit(int i) {
order[--dfsNum] = i; order[--dfsNum] = i;
} }
@Override
void doneTree() {
// do nothing
}
int[] getFinishOrder() { int[] getFinishOrder() {
search(); search();
return order; return order;
@ -131,11 +140,9 @@ public class SCC {
} }
} }
void doneVisit(int i) { abstract void doneVisit(int i);
}
void doneTree() { abstract void doneTree();
}
} }
} }

View file

@ -3,7 +3,7 @@ package org.xbib.jacc.util;
/** /**
* *
*/ */
class SeqInterator extends Interator { class SeqInterator implements Interator {
private int count; private int count;
private int limit; private int limit;
@ -13,10 +13,12 @@ class SeqInterator extends Interator {
limit = j; limit = j;
} }
@Override
public int next() { public int next() {
return count++; return count++;
} }
@Override
public boolean hasNext() { public boolean hasNext() {
return count < limit; return count < limit;
} }

View file

@ -0,0 +1,36 @@
// This file contains some simple examples of
// errors diagnostics for Calc.jacc:
"left operand is missing"
: '+' expr
| '-' expr
| '*' expr
| '/' expr
;
"unexpected closing parenthesis"
: expr ')' ;
"unexpected opening parenthesis"
: expr '(' ;
"right operand is missing"
: expr '+'
| expr '+' ')'
| expr '+' '+'
| expr '-'
| expr '-' ')'
| expr '*'
| expr '*' ')'
| expr '/'
| expr '/' ')'
;
"unnecessary semicolon after last expression (or missing expression)"
: prog ';' ;
"empty parentheses"
: '(' ')' ;
"missing expression"
: ';' ;

View file

@ -0,0 +1,7 @@
"Unexpected opening parenthesis"
: ')'
;
"Missing operand"
: expr INTEGER
;

View file

@ -0,0 +1,73 @@
package org.xbib.jacc;
import org.junit.Ignore;
import org.junit.Test;
import org.xbib.jacc.helper.StreamMatcher;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
*/
public class JaccTest {
@Test
public void calc() throws IOException {
Jacc jacc = new Jacc();
jacc.setName("Calc");
jacc.setInputStream(getResource("Calc.jacc"));
jacc.setErrorDiagnostics(getResource("Calc.errs"));
jacc.setDir("build/");
jacc.setEnableVerboseMachineDescription(true);
jacc.execute();
StreamMatcher.assertStream("CalcParser.java",
getResource("CalcParser.java"),
Files.newInputStream(Paths.get("build/CalcParser.java")));
StreamMatcher.assertStream("CalcTokens.java",
getResource("CalcTokens.java"),
Files.newInputStream(Paths.get("build/CalcTokens.java")));
StreamMatcher.assertStream("CalcParser.output",
getResource("CalcParser.output"),
Files.newInputStream(Paths.get("build/CalcParser.output")));
}
@Test
public void traceCalc() throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Jacc jacc = new Jacc();
jacc.setName("Calc");
jacc.setInputStream(getResource("Calc.jacc"));
jacc.setParserInputs(getResource("example1"));
jacc.setEnableParserOutput(false);
jacc.setEnableTokenOutput(false);
jacc.setOutputStream(byteArrayOutputStream);
jacc.setDir("build/");
jacc.execute();
StreamMatcher.assertStream("example1.out",
getResource("example1.out"),
new ByteArrayInputStream(byteArrayOutputStream.toByteArray())
);
}
@Test
public void simpleCalc() throws IOException {
Jacc jacc = new Jacc();
jacc.setName("simpleCalc");
jacc.setInputStream(getResource("simpleCalc.jacc"));
jacc.setMachineType(MachineType.SLR1);
jacc.setDir("build/");
jacc.execute();
StreamMatcher.assertStream("Calc.java",
getResource("Calc.java"),
Files.newInputStream(Paths.get("build/Calc.java")));
}
private InputStream getResource(String resource) throws IOException {
return getClass().getClassLoader().getResource("org/xbib/jacc/" + resource).openStream();
}
}

View file

@ -0,0 +1,76 @@
/*
Copyright 2016 Jörg Prante
Licensed 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 org.xbib.jacc.helper;
import org.junit.Assert;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
/**
*
*/
public class StreamMatcher extends Assert {
public static void assertStream(String name, InputStream expected, String actual) throws IOException {
assertStream(name, expected, new ByteArrayInputStream(actual.getBytes(StandardCharsets.UTF_8)));
}
public static void assertStream(String name, InputStream expected, InputStream actual) throws IOException {
int offset = 0;
ReadableByteChannel ch1 = Channels.newChannel(expected);
ReadableByteChannel ch2 = Channels.newChannel(actual);
ByteBuffer buf1 = ByteBuffer.allocateDirect(4096);
ByteBuffer buf2 = ByteBuffer.allocateDirect(4096);
try {
while (true) {
int n1 = ch1.read(buf1);
int n2 = ch2.read(buf2);
if (n1 == -1 || n2 == -1) {
if (n1 != n2) {
fail(name + ": stream length mismatch: " + n1 + " != " + n2 + " offset=" + offset);
} else {
return;
}
}
buf1.flip();
buf2.flip();
for (int i = 0; i < Math.min(n1, n2); i++) {
int b1 = buf1.get() & 0xFF;
int b2 = buf2.get() & 0xFF;
if (b1 != b2) {
fail(name + ": mismatch at offset " + (offset + i)
+ " (" + Integer.toHexString(b1)
+ " != " + Integer.toHexString(b2) + ")"
);
}
}
buf1.compact();
buf2.compact();
offset += Math.min(n1, n2);
}
} finally {
expected.close();
actual.close();
}
}
}

View file

@ -0,0 +1,4 @@
/**
* Helper classes for testing.
*/
package org.xbib.jacc.helper;

View file

@ -0,0 +1,4 @@
/**
* Classes for testing jacc.
*/
package org.xbib.jacc;

View file

@ -0,0 +1,36 @@
// This file contains some simple examples of
// errors diagnostics for Calc.jacc:
"left operand is missing"
: '+' expr
| '-' expr
| '*' expr
| '/' expr
;
"unexpected closing parenthesis"
: expr ')' ;
"unexpected opening parenthesis"
: expr '(' ;
"right operand is missing"
: expr '+'
| expr '+' ')'
| expr '+' '+'
| expr '-'
| expr '-' ')'
| expr '*'
| expr '*' ')'
| expr '/'
| expr '/' ')'
;
"unnecessary semicolon after last expression (or missing expression)"
: prog ';' ;
"empty parentheses"
: '(' ')' ;
"missing expression"
: ';' ;

View file

@ -0,0 +1,165 @@
// To compile and run this program using jacc and Sun's JDK:
//
// In a directory containing only the file Calc.jacc:
//
// jacc Calc.jacc
// javac *.java
// java CalcParser
// ... enter arithmetic expressions ... hit EOF to terminate
//
%{
abstract class Expr {
abstract int eval();
}
class IntExpr extends Expr {
private int value;
IntExpr(int value) { this.value = value; }
int eval() { return value; }
}
abstract class BinExpr extends Expr {
protected Expr left, right;
BinExpr(Expr left, Expr right) {
this.left = left; this.right = right;
}
}
class AddExpr extends BinExpr {
AddExpr(Expr left, Expr right) { super(left, right); }
int eval() { return left.eval() + right.eval(); }
}
class SubExpr extends BinExpr {
SubExpr(Expr left, Expr right) { super(left, right); }
int eval() { return left.eval() - right.eval(); }
}
class MulExpr extends BinExpr {
MulExpr(Expr left, Expr right) { super(left, right); }
int eval() { return left.eval() * right.eval(); }
}
class DivExpr extends BinExpr {
DivExpr(Expr left, Expr right) { super(left, right); }
int eval() { return left.eval() / right.eval(); }
}
class CalcLexer implements CalcTokens {
private int c = ' ';
/** Read a single input character from standard input.
*/
private void nextChar() {
if (c>=0) {
try {
c = System.in.read();
} catch (Exception e) {
c = (-1);
}
}
}
private int token;
private IntExpr yylval;
/** Read the next token and return the
* corresponding integer code.
*/
int nextToken() {
for (;;) {
// Skip whitespace
while (c==' ' || c=='\n' || c=='\t' || c=='\r') {
nextChar();
}
if (c<0) {
return (token=ENDINPUT);
}
switch (c) {
case '+' : nextChar();
return token='+';
case '-' : nextChar();
return token='-';
case '*' : nextChar();
return token='*';
case '/' : nextChar();
return token='/';
case '(' : nextChar();
return token='(';
case ')' : nextChar();
return token=')';
case ';' : nextChar();
return token=';';
default : if (Character.isDigit((char)c)) {
int n = 0;
do {
n = 10*n + (c - '0');
nextChar();
} while (Character.isDigit((char)c));
yylval = new IntExpr(n);
return token=INTEGER;
} else {
Main.error("Illegal character "+c);
nextChar();
}
}
}
}
/** Return the token code for the current lexeme.
*/
int getToken() {
return token;
}
/** Return the semantic value for the current lexeme.
*/
IntExpr getSemantic() {
return yylval;
}
}
class Main {
public static void main(String[] args) {
CalcLexer lexer = new CalcLexer();
lexer.nextToken();
CalcParser parser = new CalcParser(lexer);
parser.parse();
}
static void error(String msg) {
System.out.println("ERROR: " + msg);
System.exit(1);
}
}
%}
%semantic Expr
%token '+' '-' '*' '/' '(' ')' ';' INTEGER
%left '+' '-'
%left '*' '/'
%%
prog : prog ';' expr { System.out.println($3.eval()); }
| expr { System.out.println($1.eval()); }
;
expr : expr '+' expr { $$ = new AddExpr($1, $3); }
| expr '-' expr { $$ = new SubExpr($1, $3); }
| expr '*' expr { $$ = new MulExpr($1, $3); }
| expr '/' expr { $$ = new DivExpr($1, $3); }
| '(' expr ')' { $$ = $2; }
| INTEGER { $$ = $1; }
;
%%
private CalcLexer lexer;
CalcParser(CalcLexer lexer) { this.lexer = lexer; }
private void yyerror(String msg) {
Main.error(yyerrno<0 ? msg : yyerrmsgs[yyerrno]);
}

View file

@ -0,0 +1,536 @@
// Output created by jacc 2.1.0
public class Calc implements CalcTokens {
private int yyss = 100;
private int yytok;
private int yysp = 0;
private int[] yyst;
protected int yyerrno = (-1);
private int[] yysv;
private int yyrv;
public boolean parse() {
int yyn = 0;
yysp = 0;
yyst = new int[yyss];
yysv = new int[yyss];
yytok = (token
);
loop:
for (;;) {
switch (yyn) {
case 0:
yyst[yysp] = 0;
if (++yysp>=yyst.length) {
yyexpand();
}
case 17:
switch (yytok) {
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 1:
yyst[yysp] = 1;
if (++yysp>=yyst.length) {
yyexpand();
}
case 18:
switch (yytok) {
case ENDINPUT:
yyn = 34;
continue;
case ';':
yyn = 5;
continue;
}
yyn = 37;
continue;
case 2:
yyst[yysp] = 2;
if (++yysp>=yyst.length) {
yyexpand();
}
case 19:
yyn = yys2();
continue;
case 3:
yyst[yysp] = 3;
yysv[yysp] = (yylval
);
yytok = (yylex()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 20:
switch (yytok) {
case '(':
case error:
case INTEGER:
yyn = 37;
continue;
}
yyn = yyr8();
continue;
case 4:
yyst[yysp] = 4;
yysv[yysp] = (yylval
);
yytok = (yylex()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 21:
switch (yytok) {
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 5:
yyst[yysp] = 5;
yysv[yysp] = (yylval
);
yytok = (yylex()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 22:
switch (yytok) {
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 6:
yyst[yysp] = 6;
yysv[yysp] = (yylval
);
yytok = (yylex()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 23:
switch (yytok) {
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 7:
yyst[yysp] = 7;
yysv[yysp] = (yylval
);
yytok = (yylex()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 24:
switch (yytok) {
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 8:
yyst[yysp] = 8;
yysv[yysp] = (yylval
);
yytok = (yylex()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 25:
switch (yytok) {
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 9:
yyst[yysp] = 9;
yysv[yysp] = (yylval
);
yytok = (yylex()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 26:
switch (yytok) {
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 10:
yyst[yysp] = 10;
if (++yysp>=yyst.length) {
yyexpand();
}
case 27:
switch (yytok) {
case '*':
yyn = 6;
continue;
case '+':
yyn = 7;
continue;
case '-':
yyn = 8;
continue;
case '/':
yyn = 9;
continue;
case ')':
yyn = 16;
continue;
}
yyn = 37;
continue;
case 11:
yyst[yysp] = 11;
if (++yysp>=yyst.length) {
yyexpand();
}
case 28:
yyn = yys11();
continue;
case 12:
yyst[yysp] = 12;
if (++yysp>=yyst.length) {
yyexpand();
}
case 29:
switch (yytok) {
case '(':
case error:
case INTEGER:
yyn = 37;
continue;
}
yyn = yyr5();
continue;
case 13:
yyst[yysp] = 13;
if (++yysp>=yyst.length) {
yyexpand();
}
case 30:
switch (yytok) {
case '(':
case INTEGER:
case error:
yyn = 37;
continue;
case '*':
yyn = 6;
continue;
case '/':
yyn = 9;
continue;
}
yyn = yyr3();
continue;
case 14:
yyst[yysp] = 14;
if (++yysp>=yyst.length) {
yyexpand();
}
case 31:
switch (yytok) {
case '(':
case INTEGER:
case error:
yyn = 37;
continue;
case '*':
yyn = 6;
continue;
case '/':
yyn = 9;
continue;
}
yyn = yyr4();
continue;
case 15:
yyst[yysp] = 15;
if (++yysp>=yyst.length) {
yyexpand();
}
case 32:
switch (yytok) {
case '(':
case error:
case INTEGER:
yyn = 37;
continue;
}
yyn = yyr6();
continue;
case 16:
yyst[yysp] = 16;
yysv[yysp] = (yylval
);
yytok = (yylex()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 33:
switch (yytok) {
case '(':
case error:
case INTEGER:
yyn = 37;
continue;
}
yyn = yyr7();
continue;
case 34:
return true;
case 35:
yyerror("stack overflow");
case 36:
return false;
case 37:
yyerror("syntax error");
return false;
}
}
}
protected void yyexpand() {
int[] newyyst = new int[2*yyst.length];
int[] newyysv = new int[2*yyst.length];
for (int i=0; i<yyst.length; i++) {
newyyst[i] = yyst[i];
newyysv[i] = yysv[i];
}
yyst = newyyst;
yysv = newyysv;
}
private int yys2() {
switch (yytok) {
case '*':
return 6;
case '+':
return 7;
case '-':
return 8;
case '/':
return 9;
case ENDINPUT:
case ';':
return yyr2();
}
return 37;
}
private int yys11() {
switch (yytok) {
case '*':
return 6;
case '+':
return 7;
case '-':
return 8;
case '/':
return 9;
case ENDINPUT:
case ';':
return yyr1();
}
return 37;
}
private int yyr1() { // prog : prog ';' expr
{ System.out.println(yysv[yysp-1]); }
yysv[yysp-=3] = yyrv;
return 1;
}
private int yyr2() { // prog : expr
{ System.out.println(yysv[yysp-1]); }
yysv[yysp-=1] = yyrv;
return 1;
}
private int yyr3() { // expr : expr '+' expr
{ yyrv = yysv[yysp-3] + yysv[yysp-1]; }
yysv[yysp-=3] = yyrv;
return yypexpr();
}
private int yyr4() { // expr : expr '-' expr
{ yyrv = yysv[yysp-3] - yysv[yysp-1]; }
yysv[yysp-=3] = yyrv;
return yypexpr();
}
private int yyr5() { // expr : expr '*' expr
{ yyrv = yysv[yysp-3] * yysv[yysp-1]; }
yysv[yysp-=3] = yyrv;
return yypexpr();
}
private int yyr6() { // expr : expr '/' expr
{ yyrv = yysv[yysp-3] / yysv[yysp-1]; }
yysv[yysp-=3] = yyrv;
return yypexpr();
}
private int yyr7() { // expr : '(' expr ')'
{ yyrv = yysv[yysp-2]; }
yysv[yysp-=3] = yyrv;
return yypexpr();
}
private int yyr8() { // expr : INTEGER
{ yyrv = yysv[yysp-1]; }
yysv[yysp-=1] = yyrv;
return yypexpr();
}
private int yypexpr() {
switch (yyst[yysp-1]) {
case 8: return 14;
case 7: return 13;
case 6: return 12;
case 5: return 11;
case 4: return 10;
case 0: return 2;
default: return 15;
}
}
protected String[] yyerrmsgs = {
};
private void yyerror(String msg) {
System.out.println("ERROR: " + msg);
System.exit(1);
}
private int c;
/** Read a single input character from standard input.
*/
private void nextChar() {
if (c>=0) {
try {
c = System.in.read();
} catch (Exception e) {
c = (-1);
}
}
}
int token;
int yylval;
/** Read the next token and return the
* corresponding integer code.
*/
int yylex() {
for (;;) {
// Skip whitespace
while (c==' ' || c=='\n' || c=='\t' || c=='\r') {
nextChar();
}
if (c<0) {
return (token=ENDINPUT);
}
switch (c) {
case '+' : nextChar();
return token='+';
case '-' : nextChar();
return token='-';
case '*' : nextChar();
return token='*';
case '/' : nextChar();
return token='/';
case '(' : nextChar();
return token='(';
case ')' : nextChar();
return token=')';
case ';' : nextChar();
return token=';';
default : if (Character.isDigit((char)c)) {
int n = 0;
do {
n = 10*n + (c - '0');
nextChar();
} while (Character.isDigit((char)c));
yylval = n;
return token=INTEGER;
} else {
yyerror("Illegal character "+c);
nextChar();
}
}
}
}
public static void main(String[] args) {
Calc calc = new Calc();
calc.nextChar(); // prime the character input stream
calc.yylex(); // prime the token input stream
calc.parse(); // parse the input
}
}

View file

@ -0,0 +1,644 @@
// Output created by jacc 2.1.0
abstract class Expr {
abstract int eval();
}
class IntExpr extends Expr {
private int value;
IntExpr(int value) { this.value = value; }
int eval() { return value; }
}
abstract class BinExpr extends Expr {
protected Expr left, right;
BinExpr(Expr left, Expr right) {
this.left = left; this.right = right;
}
}
class AddExpr extends BinExpr {
AddExpr(Expr left, Expr right) { super(left, right); }
int eval() { return left.eval() + right.eval(); }
}
class SubExpr extends BinExpr {
SubExpr(Expr left, Expr right) { super(left, right); }
int eval() { return left.eval() - right.eval(); }
}
class MulExpr extends BinExpr {
MulExpr(Expr left, Expr right) { super(left, right); }
int eval() { return left.eval() * right.eval(); }
}
class DivExpr extends BinExpr {
DivExpr(Expr left, Expr right) { super(left, right); }
int eval() { return left.eval() / right.eval(); }
}
class CalcLexer implements CalcTokens {
private int c = ' ';
/** Read a single input character from standard input.
*/
private void nextChar() {
if (c>=0) {
try {
c = System.in.read();
} catch (Exception e) {
c = (-1);
}
}
}
private int token;
private IntExpr yylval;
/** Read the next token and return the
* corresponding integer code.
*/
int nextToken() {
for (;;) {
// Skip whitespace
while (c==' ' || c=='\n' || c=='\t' || c=='\r') {
nextChar();
}
if (c<0) {
return (token=ENDINPUT);
}
switch (c) {
case '+' : nextChar();
return token='+';
case '-' : nextChar();
return token='-';
case '*' : nextChar();
return token='*';
case '/' : nextChar();
return token='/';
case '(' : nextChar();
return token='(';
case ')' : nextChar();
return token=')';
case ';' : nextChar();
return token=';';
default : if (Character.isDigit((char)c)) {
int n = 0;
do {
n = 10*n + (c - '0');
nextChar();
} while (Character.isDigit((char)c));
yylval = new IntExpr(n);
return token=INTEGER;
} else {
Main.error("Illegal character "+c);
nextChar();
}
}
}
}
/** Return the token code for the current lexeme.
*/
int getToken() {
return token;
}
/** Return the semantic value for the current lexeme.
*/
IntExpr getSemantic() {
return yylval;
}
}
class Main {
public static void main(String[] args) {
CalcLexer lexer = new CalcLexer();
lexer.nextToken();
CalcParser parser = new CalcParser(lexer);
parser.parse();
}
static void error(String msg) {
System.out.println("ERROR: " + msg);
System.exit(1);
}
}
public class CalcParser implements CalcTokens {
private int yyss = 100;
private int yytok;
private int yysp = 0;
private int[] yyst;
protected int yyerrno = (-1);
private Expr[] yysv;
private Expr yyrv;
public boolean parse() {
int yyn = 0;
yysp = 0;
yyst = new int[yyss];
yyerrno = (-1);
yysv = new Expr[yyss];
yytok = (lexer.getToken()
);
loop:
for (;;) {
switch (yyn) {
case 0:
yyst[yysp] = 0;
if (++yysp>=yyst.length) {
yyexpand();
}
case 17:
yyn = yys0();
continue;
case 1:
yyst[yysp] = 1;
if (++yysp>=yyst.length) {
yyexpand();
}
case 18:
switch (yytok) {
case ENDINPUT:
yyn = 34;
continue;
case ';':
yyn = 5;
continue;
}
yyn = 37;
continue;
case 2:
yyst[yysp] = 2;
if (++yysp>=yyst.length) {
yyexpand();
}
case 19:
yyn = yys2();
continue;
case 3:
yyst[yysp] = 3;
yysv[yysp] = (lexer.getSemantic()
);
yytok = (lexer.nextToken()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 20:
switch (yytok) {
case '(':
case error:
case INTEGER:
yyn = 37;
continue;
}
yyn = yyr8();
continue;
case 4:
yyst[yysp] = 4;
yysv[yysp] = (lexer.getSemantic()
);
yytok = (lexer.nextToken()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 21:
switch (yytok) {
case ')':
yyn = yyerr(5, 37);
continue;
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 5:
yyst[yysp] = 5;
yysv[yysp] = (lexer.getSemantic()
);
yytok = (lexer.nextToken()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 22:
switch (yytok) {
case ENDINPUT:
yyn = yyerr(4, 37);
continue;
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 6:
yyst[yysp] = 6;
yysv[yysp] = (lexer.getSemantic()
);
yytok = (lexer.nextToken()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 23:
switch (yytok) {
case ENDINPUT:
case ')':
yyn = yyerr(3, 37);
continue;
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 7:
yyst[yysp] = 7;
yysv[yysp] = (lexer.getSemantic()
);
yytok = (lexer.nextToken()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 24:
switch (yytok) {
case '+':
case ENDINPUT:
case ')':
yyn = yyerr(3, 37);
continue;
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 8:
yyst[yysp] = 8;
yysv[yysp] = (lexer.getSemantic()
);
yytok = (lexer.nextToken()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 25:
switch (yytok) {
case ENDINPUT:
case ')':
yyn = yyerr(3, 37);
continue;
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 9:
yyst[yysp] = 9;
yysv[yysp] = (lexer.getSemantic()
);
yytok = (lexer.nextToken()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 26:
switch (yytok) {
case ENDINPUT:
case ')':
yyn = yyerr(3, 37);
continue;
case INTEGER:
yyn = 3;
continue;
case '(':
yyn = 4;
continue;
}
yyn = 37;
continue;
case 10:
yyst[yysp] = 10;
if (++yysp>=yyst.length) {
yyexpand();
}
case 27:
switch (yytok) {
case '*':
yyn = 6;
continue;
case '+':
yyn = 7;
continue;
case '-':
yyn = 8;
continue;
case '/':
yyn = 9;
continue;
case ')':
yyn = 16;
continue;
}
yyn = 37;
continue;
case 11:
yyst[yysp] = 11;
if (++yysp>=yyst.length) {
yyexpand();
}
case 28:
yyn = yys11();
continue;
case 12:
yyst[yysp] = 12;
if (++yysp>=yyst.length) {
yyexpand();
}
case 29:
switch (yytok) {
case '(':
case error:
case INTEGER:
yyn = 37;
continue;
}
yyn = yyr5();
continue;
case 13:
yyst[yysp] = 13;
if (++yysp>=yyst.length) {
yyexpand();
}
case 30:
switch (yytok) {
case '(':
case INTEGER:
case error:
yyn = 37;
continue;
case '*':
yyn = 6;
continue;
case '/':
yyn = 9;
continue;
}
yyn = yyr3();
continue;
case 14:
yyst[yysp] = 14;
if (++yysp>=yyst.length) {
yyexpand();
}
case 31:
switch (yytok) {
case '(':
case INTEGER:
case error:
yyn = 37;
continue;
case '*':
yyn = 6;
continue;
case '/':
yyn = 9;
continue;
}
yyn = yyr4();
continue;
case 15:
yyst[yysp] = 15;
if (++yysp>=yyst.length) {
yyexpand();
}
case 32:
switch (yytok) {
case '(':
case error:
case INTEGER:
yyn = 37;
continue;
}
yyn = yyr6();
continue;
case 16:
yyst[yysp] = 16;
yysv[yysp] = (lexer.getSemantic()
);
yytok = (lexer.nextToken()
);
if (++yysp>=yyst.length) {
yyexpand();
}
case 33:
switch (yytok) {
case '(':
case error:
case INTEGER:
yyn = 37;
continue;
}
yyn = yyr7();
continue;
case 34:
return true;
case 35:
yyerror("stack overflow");
case 36:
return false;
case 37:
yyerror("syntax error");
return false;
}
}
}
protected void yyexpand() {
int[] newyyst = new int[2*yyst.length];
Expr[] newyysv = new Expr[2*yyst.length];
for (int i=0; i<yyst.length; i++) {
newyyst[i] = yyst[i];
newyysv[i] = yysv[i];
}
yyst = newyyst;
yysv = newyysv;
}
private int yys0() {
switch (yytok) {
case ENDINPUT:
case error:
case ')':
return 37;
case ';':
return yyerr(6, 37);
case INTEGER:
return 3;
case '(':
return 4;
}
return yyerr(0, 37);
}
private int yys2() {
switch (yytok) {
case ')':
return yyerr(1, 37);
case '(':
return yyerr(2, 37);
case '*':
return 6;
case '+':
return 7;
case '-':
return 8;
case '/':
return 9;
case ENDINPUT:
case ';':
return yyr2();
}
return 37;
}
private int yys11() {
switch (yytok) {
case '*':
return 6;
case '+':
return 7;
case '-':
return 8;
case '/':
return 9;
case ENDINPUT:
case ';':
return yyr1();
}
return 37;
}
private int yyr1() { // prog : prog ';' expr
{ System.out.println(yysv[yysp-1].eval()); }
yysv[yysp-=3] = yyrv;
return 1;
}
private int yyr2() { // prog : expr
{ System.out.println(yysv[yysp-1].eval()); }
yysv[yysp-=1] = yyrv;
return 1;
}
private int yyr3() { // expr : expr '+' expr
{ yyrv = new AddExpr(yysv[yysp-3], yysv[yysp-1]); }
yysv[yysp-=3] = yyrv;
return yypexpr();
}
private int yyr4() { // expr : expr '-' expr
{ yyrv = new SubExpr(yysv[yysp-3], yysv[yysp-1]); }
yysv[yysp-=3] = yyrv;
return yypexpr();
}
private int yyr5() { // expr : expr '*' expr
{ yyrv = new MulExpr(yysv[yysp-3], yysv[yysp-1]); }
yysv[yysp-=3] = yyrv;
return yypexpr();
}
private int yyr6() { // expr : expr '/' expr
{ yyrv = new DivExpr(yysv[yysp-3], yysv[yysp-1]); }
yysv[yysp-=3] = yyrv;
return yypexpr();
}
private int yyr7() { // expr : '(' expr ')'
{ yyrv = yysv[yysp-2]; }
yysv[yysp-=3] = yyrv;
return yypexpr();
}
private int yyr8() { // expr : INTEGER
{ yyrv = yysv[yysp-1]; }
yysv[yysp-=1] = yyrv;
return yypexpr();
}
private int yypexpr() {
switch (yyst[yysp-1]) {
case 8: return 14;
case 7: return 13;
case 6: return 12;
case 5: return 11;
case 4: return 10;
case 0: return 2;
default: return 15;
}
}
private int yyerr(int e, int n) {
yyerrno = e;
return n;
}
protected String[] yyerrmsgs = {
"left operand is missing",
"unexpected closing parenthesis",
"unexpected opening parenthesis",
"right operand is missing",
"unnecessary semicolon after last expression (or missing expression)",
"empty parentheses",
"missing expression"
};
private CalcLexer lexer;
CalcParser(CalcLexer lexer) { this.lexer = lexer; }
private void yyerror(String msg) {
Main.error(yyerrno<0 ? msg : yyerrmsgs[yyerrno]);
}
}

View file

@ -0,0 +1,203 @@
// Output created by jacc 2.1.0
state 0 (entry on prog)
$accept : _prog $end
$end error
error error
')' error
';' error "missing expression"
INTEGER shift 3
'(' shift 4
. error "left operand is missing"
prog goto 1
expr goto 2
state 1 (entry on prog)
$accept : prog_$end
prog : prog_';' expr (1)
$end accept
';' shift 5
. error
state 2 (entry on expr)
prog : expr_ (2)
expr : expr_'+' expr (3)
expr : expr_'-' expr (4)
expr : expr_'*' expr (5)
expr : expr_'/' expr (6)
')' error "unexpected closing parenthesis"
'(' error "unexpected opening parenthesis"
'*' shift 6
'+' shift 7
'-' shift 8
'/' shift 9
$end reduce 2
';' reduce 2
. error
state 3 (entry on INTEGER)
expr : INTEGER_ (8)
'(' error
error error
INTEGER error
. reduce 8
state 4 (entry on '(')
expr : '('_expr ')' (7)
')' error "empty parentheses"
INTEGER shift 3
'(' shift 4
. error
expr goto 10
state 5 (entry on ';')
prog : prog ';'_expr (1)
$end error "unnecessary semicolon after last expression (or missing expression)"
INTEGER shift 3
'(' shift 4
. error
expr goto 11
state 6 (entry on '*')
expr : expr '*'_expr (5)
$end error "right operand is missing"
')' error "right operand is missing"
INTEGER shift 3
'(' shift 4
. error
expr goto 12
state 7 (entry on '+')
expr : expr '+'_expr (3)
'+' error "right operand is missing"
$end error "right operand is missing"
')' error "right operand is missing"
INTEGER shift 3
'(' shift 4
. error
expr goto 13
state 8 (entry on '-')
expr : expr '-'_expr (4)
$end error "right operand is missing"
')' error "right operand is missing"
INTEGER shift 3
'(' shift 4
. error
expr goto 14
state 9 (entry on '/')
expr : expr '/'_expr (6)
$end error "right operand is missing"
')' error "right operand is missing"
INTEGER shift 3
'(' shift 4
. error
expr goto 15
state 10 (entry on expr)
expr : expr_'+' expr (3)
expr : expr_'-' expr (4)
expr : expr_'*' expr (5)
expr : expr_'/' expr (6)
expr : '(' expr_')' (7)
'*' shift 6
'+' shift 7
'-' shift 8
'/' shift 9
')' shift 16
. error
state 11 (entry on expr)
prog : prog ';' expr_ (1)
expr : expr_'+' expr (3)
expr : expr_'-' expr (4)
expr : expr_'*' expr (5)
expr : expr_'/' expr (6)
'*' shift 6
'+' shift 7
'-' shift 8
'/' shift 9
$end reduce 1
';' reduce 1
. error
state 12 (entry on expr)
expr : expr_'+' expr (3)
expr : expr_'-' expr (4)
expr : expr_'*' expr (5)
expr : expr '*' expr_ (5)
expr : expr_'/' expr (6)
'(' error
error error
INTEGER error
. reduce 5
state 13 (entry on expr)
expr : expr_'+' expr (3)
expr : expr '+' expr_ (3)
expr : expr_'-' expr (4)
expr : expr_'*' expr (5)
expr : expr_'/' expr (6)
'(' error
INTEGER error
error error
'*' shift 6
'/' shift 9
. reduce 3
state 14 (entry on expr)
expr : expr_'+' expr (3)
expr : expr_'-' expr (4)
expr : expr '-' expr_ (4)
expr : expr_'*' expr (5)
expr : expr_'/' expr (6)
'(' error
INTEGER error
error error
'*' shift 6
'/' shift 9
. reduce 4
state 15 (entry on expr)
expr : expr_'+' expr (3)
expr : expr_'-' expr (4)
expr : expr_'*' expr (5)
expr : expr_'/' expr (6)
expr : expr '/' expr_ (6)
'(' error
error error
INTEGER error
. reduce 6
state 16 (entry on ')')
expr : '(' expr ')'_ (7)
'(' error
error error
INTEGER error
. reduce 7
10 terminals, 2 nonterminals;8 grammar rules, 17 states;0 shift/reduce and 0 reduce/reduce conflicts reported.

View file

@ -0,0 +1,13 @@
// Output created by jacc 2.1.0
interface CalcTokens {
int ENDINPUT = 0;
int INTEGER = 1;
int error = 2;
// '(' (code=40)
// ')' (code=41)
// '*' (code=42)
// '+' (code=43)
// '-' (code=45)
// '/' (code=47)
// ';' (code=59)
}

View file

@ -0,0 +1,4 @@
INTEGER '+' INTEGER '*' INTEGER ';'
INTEGER '*' INTEGER '+' INTEGER

View file

@ -0,0 +1,38 @@
Running example from input stream
start : _ INTEGER ...
shift : INTEGER _ '+' ...
reduce : _ expr '+' ...
goto : expr _ '+' ...
shift : expr '+' _ INTEGER ...
shift : expr '+' INTEGER _ '*' ...
reduce : expr '+' _ expr '*' ...
goto : expr '+' expr _ '*' ...
shift : expr '+' expr '*' _ INTEGER ...
shift : expr '+' expr '*' INTEGER _ ';' ...
reduce : expr '+' expr '*' _ expr ';' ...
goto : expr '+' expr '*' expr _ ';' ...
reduce : expr '+' _ expr ';' ...
goto : expr '+' expr _ ';' ...
reduce : _ expr ';' ...
goto : expr _ ';' ...
reduce : _ prog ';' ...
goto : prog _ ';' ...
shift : prog ';' _ INTEGER ...
shift : prog ';' INTEGER _ '*' ...
reduce : prog ';' _ expr '*' ...
goto : prog ';' expr _ '*' ...
shift : prog ';' expr '*' _ INTEGER ...
shift : prog ';' expr '*' INTEGER _ '+' ...
reduce : prog ';' expr '*' _ expr '+' ...
goto : prog ';' expr '*' expr _ '+' ...
reduce : prog ';' _ expr '+' ...
goto : prog ';' expr _ '+' ...
shift : prog ';' expr '+' _ INTEGER ...
shift : prog ';' expr '+' INTEGER _
reduce : prog ';' expr '+' _ expr $end
goto : prog ';' expr '+' expr _ $end
reduce : prog ';' _ expr $end
goto : prog ';' expr _ $end
reduce : _ prog $end
goto : prog _ $end
Accept!

View file

@ -0,0 +1,104 @@
// To compile and run this program using jacc and Sun's JDK:
//
// jacc simpleCalc.jacc
// javac Calc.java CalcTokens.java
// java Calc
// ... enter arithmetic expressions ... hit EOF to terminate
//
%class Calc
%interface CalcTokens
%semantic int : yylval
%get token
%next yylex()
%token '+' '-' '*' '/' '(' ')' ';' INTEGER
%left '+' '-'
%left '*' '/'
%%
prog : prog ';' expr { System.out.println($3); }
| expr { System.out.println($1); }
;
expr : expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr { $$ = $1 / $3; }
| '(' expr ')' { $$ = $2; }
| INTEGER { $$ = $1; }
;
%%
private void yyerror(String msg) {
System.out.println("ERROR: " + msg);
System.exit(1);
}
private int c;
/** Read a single input character from standard input.
*/
private void nextChar() {
if (c>=0) {
try {
c = System.in.read();
} catch (Exception e) {
c = (-1);
}
}
}
int token;
int yylval;
/** Read the next token and return the
* corresponding integer code.
*/
int yylex() {
for (;;) {
// Skip whitespace
while (c==' ' || c=='\n' || c=='\t' || c=='\r') {
nextChar();
}
if (c<0) {
return (token=ENDINPUT);
}
switch (c) {
case '+' : nextChar();
return token='+';
case '-' : nextChar();
return token='-';
case '*' : nextChar();
return token='*';
case '/' : nextChar();
return token='/';
case '(' : nextChar();
return token='(';
case ')' : nextChar();
return token=')';
case ';' : nextChar();
return token=';';
default : if (Character.isDigit((char)c)) {
int n = 0;
do {
n = 10*n + (c - '0');
nextChar();
} while (Character.isDigit((char)c));
yylval = n;
return token=INTEGER;
} else {
yyerror("Illegal character "+c);
nextChar();
}
}
}
}
public static void main(String[] args) {
Calc calc = new Calc();
calc.nextChar(); // prime the character input stream
calc.yylex(); // prime the token input stream
calc.parse(); // parse the input
}