--- /dev/null
+package org.simantics.scl.compiler.parser.generator.java;
+
+import gnu.trove.set.hash.THashSet;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.simantics.scl.compiler.parser.generator.compression.CompressedParseTable;
+import org.simantics.scl.compiler.parser.generator.grammar.AnaGrammar;
+import org.simantics.scl.compiler.parser.generator.grammar.Prod;
+
+public class GenerateParser {
+
+ String packageName;
+ String className;
+ String exceptionName;
+ AnaGrammar grammar;
+ CompressedParseTable table;
+
+ public GenerateParser(String packageName, String className,
+ AnaGrammar grammar, String exceptionName, CompressedParseTable table) {
+ this.packageName = packageName;
+ this.className = className;
+ this.grammar = grammar;
+ this.exceptionName = exceptionName;
+ this.table = table;
+ }
+
+ private String readTemplate() throws IOException {
+ InputStream stream = getClass().getResourceAsStream("Parser.java.template");
+ byte[] buffer = new byte[10000];
+ int pos = 0;
+ while(true) {
+ int c = stream.read(buffer, pos, buffer.length-pos);
+ if(c <= 0)
+ break;
+ pos += c;
+ if(pos == buffer.length)
+ buffer = Arrays.copyOf(buffer, buffer.length*2);
+ }
+ return new String(buffer, 0, pos, "UTF-8");
+ }
+
+ private static final Pattern PATTERN = Pattern.compile("\\$[A-Za-z0-9]+\\$");
+
+ public void generate(File file) throws IOException {
+ PrintStream out = new PrintStream(file, "UTF-8");
+
+ int aPos = 0;
+ String template = readTemplate();
+ Matcher matcher = PATTERN.matcher(template);
+ while(matcher.find()) {
+ int start = matcher.start();
+ int end = matcher.end();
+ out.print(template.substring(aPos, start));
+ String varName = template.substring(start+1, end-1);
+ generateVar(out, varName);
+ aPos = end;
+ }
+ out.print(template.substring(aPos));
+
+ out.close();
+ }
+
+ private void generateVar(PrintStream out, String varName) {
+ if("package".equals(varName)) {
+ out.print(packageName);
+ }
+ else if("class".equals(varName)) {
+ out.print(className);
+ }
+ else if("terminalCount".equals(varName)) {
+ out.print(grammar.terminalNames.length);
+ }
+ else if("nonterminalCount".equals(varName)) {
+ out.print(grammar.nonterminalNames.length);
+ }
+ else if("productCount".equals(varName)) {
+ out.print(grammar.prods.size());
+ }
+ else if("stateCount".equals(varName)) {
+ out.print(table.actionTable.rowIndex.length);
+ }
+ else if("parseMethods".equals(varName)) {
+ for(int i=0;i<grammar.initialNonterminals.length;++i) {
+ String ntName = grammar.getName(grammar.initialNonterminals[i]);
+ ntName = ntName.substring(0, 1).toUpperCase() + ntName.substring(1);
+ out.println(" public Object parse" + ntName + "() {");
+ out.println(" return parse(" + table.initialStates[i] + ");");
+ out.println(" }");
+ }
+ }
+ else if("terminalNames".equals(varName)) {
+ for(int i=0;i<grammar.terminalNames.length;++i) {
+ if(i > 0)
+ out.println(",");
+ out.print(" \"" + grammar.terminalNames[i] + "\"");
+ }
+ }
+ else if("nonterminalNames".equals(varName)) {
+ for(int i=0;i<grammar.nonterminalNames.length;++i) {
+ if(i > 0)
+ out.println(",");
+ out.print(" \"" + grammar.nonterminalNames[i] + "\"");
+ }
+ }
+ else if("stateDescriptions".equals(varName)) {
+ for(int i=0;i<table.stateDescriptions.length;++i) {
+ if(i > 0)
+ out.println(",");
+ out.print(" \"" + table.stateDescriptions[i].replace("\n", "\\n") + "\"");
+ }
+ }
+ else if("reduceCases".equals(varName)) {
+ for(int i=0;i<grammar.prods.size();++i) {
+ Prod prod = grammar.prods.get(i);
+ if(grammar.nonterminalNames[prod.lhs].startsWith("init$"))
+ continue;
+ out.println(" case " + i + ":");
+ out.println(" return reduce" + prod.name + "();");
+ }
+ }
+ else if("reduceDelegates".equals(varName)) {
+ for(int i=0;i<grammar.prods.size();++i) {
+ Prod prod = grammar.prods.get(i);
+ if(grammar.nonterminalNames[prod.lhs].startsWith("init$"))
+ out.println(" null,");
+ else {
+ out.println(" new ReduceDelegate() {");
+ out.println(" public Object reduce(" + className + " parser) {");
+ out.println(" return parser.reduce" + prod.name + "();");
+ out.println(" }");
+ out.println(" },");
+ }
+ }
+ }
+ else if("reduceMethods".equals(varName)) {
+ THashSet<String> usedNames = new THashSet<String>();
+ for(int i=0;i<grammar.prods.size();++i) {
+ Prod prod = grammar.prods.get(i);
+ if(grammar.nonterminalNames[prod.lhs].startsWith("init$"))
+ continue;
+ if(usedNames.add(prod.name)) {
+ out.println(" /**");
+ out.println(" * " + prod.toString(grammar).replace("*", "*"));
+ out.println(" */");
+ out.println(" protected abstract Object reduce" + prod.name + "();");
+ }
+ }
+ }
+ else if("Token".equals(varName)) {
+ out.print("Token");
+ }
+ else if("Symbol".equals(varName)) {
+ out.print("Object");
+ }
+ else if("tokenId".equals(varName)) {
+ out.print("id");
+ }
+ else if("imports".equals(varName)) {
+ out.println("import org.simantics.scl.compiler.internal.parsing.Token;");
+ }
+ else if("actionTableLength".equals(varName)) {
+ out.print(table.actionTable.table.length);
+ }
+ else if("gotoTableLength".equals(varName)) {
+ out.print(table.gotoTable.table.length);
+ }
+ else if("errorTableLength".equals(varName)) {
+ out.print(table.errorTable.length);
+ }
+ else if("Exception".equals(varName)) {
+ out.print(exceptionName);
+ }
+ }
+
+}