/*
* xtc - The eXTensible Compiler
* Copyright (C) 2009-2012 New York University
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package xtc.lang.cpp;
import java.lang.*;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.HashMap;
/**
* This class generates a base class for semantic actions for a
* grammar. It takes "name, type" pairs from the standard input.
*
* @author Paul Gazzillo
* @version $Revision: 1.9 $
*/
public class GenerateValuesClass {
public static void main(String args[]) throws Exception {
BufferedReader inputStream = null;
PrintWriter outputStream = null;
if (args.length != 2) {
System.err.println("USAGE: GenerateValuesClass outClassName"
+ " parseTablesClassName");
System.exit(1);
}
String outClassName = args[0];
String parseTablesClassName = args[1];
ParseTables parseTables
= (ParseTables) Class.forName(parseTablesClassName).newInstance();
try {
outputStream = new PrintWriter(System.out);
outputStream.print("" +
"/*\n" +
" * xtc - The eXTensible Compiler\n" +
" * Copyright (C) 2009-2012 New York University\n" +
" *\n" +
" * This program is free software; you can redistribute it and/or\n" +
" * modify it under the terms of the GNU General Public License\n" +
" * version 2 as published by the Free Software Foundation.\n" +
" *\n" +
" * This program is distributed in the hope that it will be useful,\n" +
" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +
" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +
" * GNU General Public License for more details.\n" +
" *\n" +
" * You should have received a copy of the GNU General Public License\n" +
" * along with this program; if not, write to the Free Software\n" +
" * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,\n" +
" * USA.\n" +
" */\n" +
"package xtc.lang.cpp;\n" +
"\n" +
"import xtc.lang.cpp.ForkMergeParser.Subparser;\n" +
"import xtc.tree.GNode;\n" +
"import xtc.util.Pair;" +
"\n" +
"/**\n" +
" * This class is generated from grammar annotations and provides semantic\n" +
" * value and action support.\n" +
" */\n"
);
inputStream = new BufferedReader(new InputStreamReader(System.in));
HashSet<Integer> list = new HashSet<Integer>();
HashSet<Integer> layout = new HashSet<Integer>();
HashMap<Integer, String> action = new HashMap<Integer, String>();
HashSet<Integer> passthrough = new HashSet<Integer>();
HashSet<Integer> complete = new HashSet<Integer>();
HashSet<Integer> voidSymbol = new HashSet<Integer>();
HashMap<Integer, String> symbolName = new HashMap<Integer, String>();
String l;
while ((l = inputStream.readLine()) != null) {
String[] a = l.split(" ");
String name = a[0];
String type = a[1];
String parm = a.length > 2 ? a[2] : null;
int sym = -1;
for (int i = 0; i < parseTables.yytname.length; i++) {
if (parseTables.yytname[i].equals(name)) {
sym = i;
break;
}
}
if (sym >= 0) {
if (type.equals("list")) {
list.add(sym);
} else if (type.equals("layout")) {
layout.add(sym);
} else if (type.equals("action")) {
action.put(sym, name);
complete.add(sym);
} else if (type.equals("passthrough")) {
passthrough.add(sym);
} else if (type.equals("complete")) {
complete.add(sym);
} else if (type.equals("void")) {
voidSymbol.add(sym);
} else if (type.equals("name")) {
symbolName.put(sym, parm);
} else {
System.err.println("error: node " + name + " has unknown " +
"type " + type);
}
} else {
System.err.println("error: there is no node " + name + " in the " +
"grammar");
}
}
// Add support for automatically identifying inline, mid-rule
// actions.
for (int sym = 0; sym < parseTables.yytname.length; sym++) {
String name = parseTables.yytname[sym];
if (name.startsWith("$@")) {
action.put(sym, name);
complete.add(sym); // all inline action nodes should be
// complete lest they prevent merging!
}
}
outputStream.print("" +
"public class " + outClassName + " implements SemanticValues {\n" +
" private static " + outClassName + " ref;\n" +
"\n" +
" public static " + outClassName + " getInstance() {\n" +
" if (ref == null)\n" +
" ref = new " + outClassName + "();\n" +
" return ref;\n" +
" }\n" +
"\n"
);
outputStream.print("" +
" public Object getValue(int id, String name, Pair<Object> values) {\n" +
" Object value;\n" +
"\n" +
" if (values == Pair.<Object>empty()) {\n" +
" value = GNode.create(name);\n" +
"\n" +
" } else {\n" +
" value = GNode.createFromPair(name, values.head(), values.tail());\n" +
" }\n" +
"\n" +
" return value;\n" +
" }\n" +
"");
outputStream.print("" +
" public ValueType getValueType(int id) {\n");
// Find out the ranges [0,frontStreak) and (backStreak,SIZE)
// where production id is the default NODE types.
int frontStreak, backStreak;
for (frontStreak = 0;
frontStreak < parseTables.yytname.length
&& ! list.contains(frontStreak)
&& ! layout.contains(frontStreak)
&& ! action.containsKey(frontStreak)
&& ! passthrough.contains(frontStreak);
frontStreak++);
for (backStreak = parseTables.yytname.length - 1;
backStreak >= 0
&& ! list.contains(backStreak)
&& ! layout.contains(backStreak)
&& ! action.containsKey(backStreak)
&& ! passthrough.contains(backStreak);
backStreak--);
outputStream.print("" +
" if (0 <= id && id < " + frontStreak);
if (backStreak < parseTables.yytname.length - 1) {
outputStream.print("" +
" || " + backStreak + " < id");
}
outputStream.print("" +
") {\n" +
" return ValueType.NODE;\n" +
" }\n");
int c; // Used to emit return statement;
outputStream.print("" +
" switch (id - " + frontStreak + ") {\n");
c = 0;
for (int i = 0; i < parseTables.yytname.length; i++) {
if (list.contains(i)) {
outputStream.print("" +
" case " + (i - frontStreak) + ": // " + parseTables.yytname[i] + " (" + i + ")\n");
if (c < list.size() - 1) {
outputStream.print("" +
" // Fall through\n");
} else {
outputStream.print("" +
" return ValueType.LIST;\n\n");
}
c++;
}
}
c = 0;
for (int i = 0; i < parseTables.yytname.length; i++) {
if (layout.contains(i)) {
outputStream.print("" +
" case " + (i - frontStreak) + ": // " + parseTables.yytname[i] + " (" + i + ")\n");
if (c < layout.size() - 1) {
outputStream.print("" +
" // Fall through\n");
} else {
outputStream.print("" +
" return ValueType.LAYOUT;\n\n");
}
c++;
}
}
c = 0;
for (int i = 0; i < parseTables.yytname.length; i++) {
if (action.containsKey(i)) {
outputStream.print("" +
" case " + (i - frontStreak) + ": // " + parseTables.yytname[i] + " (" + i + ")\n");
if (c < action.keySet().size() - 1) {
outputStream.print("" +
" // Fall through\n");
} else {
outputStream.print("" +
" return ValueType.ACTION;\n\n");
}
c++;
}
}
c = 0;
for (int i = 0; i < parseTables.yytname.length; i++) {
if (passthrough.contains(i)) {
outputStream.print("" +
" case " + (i - frontStreak) + ": // " + parseTables.yytname[i] + " (" + i + ")\n");
if (c < passthrough.size() - 1) {
outputStream.print("" +
" // Fall through\n");
} else {
outputStream.print("" +
" return ValueType.PASS_THROUGH;\n\n");
}
c++;
}
}
c = 0;
for (int i = 0; i < parseTables.yytname.length; i++) {
if (voidSymbol.contains(i)) {
outputStream.print("" +
" case " + (i - frontStreak) + ": // " + parseTables.yytname[i] + " (" + i + ")\n");
if (c < voidSymbol.size() - 1) {
outputStream.print("" +
" // Fall through\n");
} else {
outputStream.print("" +
" return ValueType.VOID;\n\n");
}
c++;
}
}
outputStream.print("" +
" default:\n" +
" return ValueType.NODE;\n" +
" }\n" +
" }\n");
outputStream.print("" +
" public boolean isComplete(int id) {\n" +
" switch(id) {\n");
c = 0;
for (Integer i : complete) {
outputStream.print("" +
" case " + i + ": " + "// " + parseTables.yytname[i] + "\n");
if (c < complete.size() - 1) {
outputStream.print("" +
" // Fall through\n");
} else {
outputStream.print("" +
" return true;\n\n");
}
c++;
}
outputStream.print("" +
" default:\n" +
" return false;\n" +
" }\n" +
" }\n" +
"\n");
outputStream.print("" +
" public boolean changeName(int id) {\n" +
" switch(id) {\n");
c = 0;
for (Integer i : symbolName.keySet()) {
outputStream.print("" +
" case " + i + ": " + "// " + parseTables.yytname[i] + "\n");
if (c < symbolName.size() - 1) {
outputStream.print("" +
" // Fall through\n");
} else {
outputStream.print("" +
" return true;\n\n");
}
c++;
}
outputStream.print("" +
" default:\n" +
" return false;\n" +
" }\n" +
" }\n" +
"\n");
outputStream.print("" +
" public String newName(int id) {\n" +
" switch(id) {\n");
c = 0;
for (Integer i : symbolName.keySet()) {
outputStream.print("" +
" case " + i + ": " + "// " + parseTables.yytname[i] + "\n");
if (c < symbolName.size() - 1) {
outputStream.print("" +
" // Fall through\n");
} else {
outputStream.print("" +
" return \"" + symbolName.get(i) + "\";\n\n");
}
c++;
}
outputStream.print("" +
" default:\n" +
" return null;\n" +
" }\n" +
" }\n" +
"\n");
outputStream.print("" +
"\n" +
"}\n");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}
}