/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This file is part of SableCC. *
* See the file "LICENSE" for copyright information and the *
* terms and conditions for copying, distribution and *
* modification of SableCC. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package org.sablecc.sablecc;
import org.sablecc.sablecc.analysis.*;
import org.sablecc.sablecc.node.*;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@SuppressWarnings({"rawtypes", "unchecked"})
public class ResolveIds extends DepthFirstAdapter {
public final Map helpers = new TypedTreeMap(
StringComparator.instance,
StringCast.instance,
NodeCast.instance);
public final Map states = new TypedTreeMap(
StringComparator.instance,
StringCast.instance,
NodeCast.instance);
public final Map tokens = new TypedTreeMap(
StringComparator.instance,
StringCast.instance,
NodeCast.instance);
public final Map ignTokens = new TypedTreeMap(
StringComparator.instance,
StringCast.instance,
NodeCast.instance);
public final Map prods = new TypedTreeMap(
StringComparator.instance,
StringCast.instance,
NodeCast.instance);
public final Map alts = new TypedHashMap(
StringCast.instance,
NodeCast.instance);
public final Map elems = new TypedHashMap(
StringCast.instance,
NodeCast.instance);
public final Map names = new TypedHashMap(
NodeCast.instance,
StringCast.instance);
public final Map errorNames = new TypedHashMap(
NodeCast.instance,
StringCast.instance);
public final Map elemTypes = new TypedHashMap(
NodeCast.instance,
StringCast.instance);
public final Map altsElemNameTypes = new TypedHashMap(
StringCast.instance,
StringCast.instance);
// This map will serve for simpleTerm and simplelistTerm type within an altTransform
// Inside an altTransform, one would look at this map to know its type. (P... or T...)
public final Map altsElemTypes = new TypedHashMap(
StringCast.instance,
StringCast.instance);
public final Map fixedTokens = new TypedHashMap(
NodeCast.instance,
BooleanCast.instance);
public final List tokenList = new TypedLinkedList(StringCast.instance);
public final LinkedList stateList = new TypedLinkedList(StringCast.instance);
public File pkgDir;
public String pkgName = "";
// private boolean processingStates;
// private boolean processingIgnTokens;
String currentProd;
String currentAlt;
private int lastLine;
private int lastPos;
public ResolveIds(File currentDir) {
pkgDir = currentDir;
}
@Override
public void inAGrammar(AGrammar node) {
TPkgId[] temp = (TPkgId[]) node.getPackage().toArray(new TPkgId[0]);
if (temp.length > 0) {
pkgName = temp[0].getText();
pkgDir = new File(pkgDir, temp[0].getText());
for (int i = 1; i < temp.length; i++) {
pkgName += "." + temp[i].getText();
pkgDir = new File(pkgDir, temp[i].getText());
}
if (!pkgDir.exists()) {
if (!pkgDir.mkdirs()) {
throw new RuntimeException("Unable to create " + pkgDir.getAbsolutePath());
}
}
}
}
@Override
public void caseAProd(AProd node) {
//inAProd code.
currentProd = name(node.getId().getText());
String name = "P" + currentProd;
if (prods.put(name, node) != null) {
error(node.getId(), name);
}
names.put(node, name);
//list of inAAlt code.
Object[] list_alt = (Object[]) node.getAlts().toArray();
for (int i = 0; i < list_alt.length; i++) {
((PAlt) list_alt[i]).apply(this);
}
}
@Override
public void caseAIdBasic(AIdBasic node) {
String name = node.getId().getText();
// Only helpers can be used inside tokens definition
if (helpers.get(name) == null) {
error2(node.getId(), name);
}
}
@Override
public void outAHelperDef(AHelperDef node) {
String name = node.getId().getText();
// IfStmt another helper is used within the current helper,
// it should have been defined before the current one
if (helpers.put(name, node) != null) {
error(node.getId(), name);
}
names.put(node, name);
}
@Override
public void outATokenDef(ATokenDef node) {
String name = "T" + name(node.getId().getText());
String errorName = errorName(node.getId().getText());
//We are making sure that this token is not yet defined.
if (tokens.put(name, node) != null) {
error(node.getId(), name);
}
names.put(node, name);
errorNames.put(node, errorName);
tokenList.add(name);
if (node.getLookAhead() != null) {
Token token = (Token) node.getSlash();
throw new RuntimeException(
"[" + token.getLine() + "," + token.getPos() + "] " +
"Look ahead not yet supported.");
}
}
@Override
public void inAStates(AStates node) {
Object[] list_id = (Object[]) node.getListId().toArray();
String name;
for (int i = 0; i < list_id.length; i++) {
name = ((TId) list_id[i]).getText().toUpperCase();
if (states.put(name, list_id[i]) != null) {
error((TId) list_id[i], name);
}
names.put(list_id[i], name);
stateList.add(name);
}
}
@Override
public void inAIgnTokens(AIgnTokens node) {
Object[] list_id = (Object[]) node.getListId().toArray();
String name;
for (int i = 0; i < list_id.length; i++) {
name = "T" + name(((TId) list_id[i]).getText());
if (tokens.get(name) == null) {
error2((TId) list_id[i], name);
}
if (ignTokens.put(name, list_id[i]) != null) {
error((TId) list_id[i], name);
}
names.put(list_id[i], name);
}
}
private Map stateMap;
@Override
public void inAStateList(AStateList node) {
stateMap = new TypedTreeMap(
StringComparator.instance,
StringCast.instance,
NodeCast.instance);
String name = node.getId().getText().toUpperCase();
if (states.get(name) == null) {
error2(node.getId(), name);
}
if (stateMap.put(name, node) != null) {
error(node.getId(), name);
}
}
@Override
public void outAStateList(AStateList node) {
stateMap = null;
}
@Override
public void inAStateListTail(AStateListTail node) {
String name = node.getId().getText().toUpperCase();
if (states.get(name) == null) {
error2(node.getId(), name);
}
if (stateMap.put(name, node) != null) {
error(node.getId(), name);
}
}
@Override
public void inATransition(ATransition node) {
String name = node.getId().getText().toUpperCase();
if (states.get(name) == null) {
error2(node.getId(), name);
}
}
@Override
public void caseAAlt(final AAlt alt) {
if (alt.getAltName() != null) {
currentAlt =
"A" +
name(alt.getAltName().getText()) +
currentProd;
if (alts.put(currentAlt, alt) != null) {
error(alt.getAltName(), currentAlt);
}
names.put(alt, currentAlt);
} else {
currentAlt = "A" + currentProd;
if (alts.put(currentAlt, alt) != null) {
error(currentAlt);
}
names.put(alt, currentAlt);
}
AElem list_elem[] = (AElem[]) alt.getElems().toArray(new AElem[0]);
for (int i = 0; i < list_elem.length; i++) {
list_elem[i].apply(this);
}
}
public void defaultcase(Node node) {
if (node instanceof Token) {
Token t = (Token) node;
lastLine = t.getLine();
lastPos = t.getPos() + t.getText().length();
}
}
@Override
public void caseAAst(AAst node) {
}
@Override
public void caseAElem(final AElem elem) {
if (elem.getElemName() != null) {
String name = currentAlt + "." +
name(elem.getElemName().getText());
if (elems.put(name, elem) != null) {
error(elem.getElemName(), name);
}
if (elem.getElemName().getText().equals("class")) {
error5(elem.getElemName());
}
names.put(elem, name(elem.getElemName().getText()));
} else {
String name = currentAlt + "." +
name(elem.getId().getText());
if (elems.put(name, elem) != null) {
error(elem.getId(), name);
}
if (elem.getId().getText().equals("class")) {
error5(elem.getId());
}
names.put(elem, name(elem.getId().getText()));
}
}
@Override
public void outAProductions(AProductions prod) {
prod.apply(new DepthFirstAdapter() {
@Override
public void caseAProd(AProd node) {
//inAProd code.
currentProd = name(node.getId().getText());
//list of inAAlt code.
Object[] list_alt = (Object[]) node.getAlts().toArray();
for (int i = 0; i < list_alt.length; i++) {
((PAlt) list_alt[i]).apply(this);
}
}
@Override
public void caseAAlt(final AAlt alt) {
if (alt.getAltName() != null) {
currentAlt = "A" + name(alt.getAltName().getText()) + currentProd;
} else {
currentAlt = "A" + currentProd;
}
AElem[] list_elem = (AElem[]) alt.getElems().toArray(new AElem[0]);
for (int i = 0; i < list_elem.length; i++) {
list_elem[i].apply(this);
}
}
@Override
public void caseAElem(AElem node) {
String name = name(node.getId().getText());
String nameOfElem;
if (node.getElemName() != null) {
nameOfElem = node.getElemName().getText();
} else {
nameOfElem = node.getId().getText();
}
if (node.getSpecifier() != null) {
if (node.getSpecifier() instanceof ATokenSpecifier) {
if (tokens.get("T" + name) == null) {
error2(node.getId(), "T" + name);
}
if (ignTokens.get("T" + name) != null) {
error3(node.getId(), "T" + name);
}
elemTypes.put(node, "T" + name);
if (node.getElemName() != null) {
altsElemNameTypes.put(currentAlt + "." + node.getElemName().getText(), "T" + name);
}
String type_name = name;
if (node.getUnOp() instanceof AStarUnOp || node.getUnOp() instanceof AQMarkUnOp) {
type_name += "?";
}
altsElemTypes.put(currentAlt + "." + nameOfElem, "T" + type_name);
} else {
if (prods.get("P" + name) == null) {
error2(node.getId(), "P" + name);
}
elemTypes.put(node, "P" + name);
if (node.getElemName() != null) {
altsElemNameTypes.put(currentAlt + "." + node.getElemName().getText(), "P" + name);
}
//altsElemTypes.put(currentAlt+"." + nameOfElem, "P" + name);
String type_name = name;
if (node.getUnOp() instanceof AStarUnOp || node.getUnOp() instanceof AQMarkUnOp) {
type_name += "?";
}
altsElemTypes.put(currentAlt + "." + nameOfElem, "P" + type_name);
}
} else {
Object token = tokens.get("T" + name);
Object ignToken = ignTokens.get("T" + name);
Object production = prods.get("P" + name);
if ((token == null) && (production == null)) {
error2(node.getId(), "P" + name + " and T" + name);
}
if (token != null) {
if (production != null) {
error4(node.getId(), "P" + name + " and T" + name);
}
if (ignToken != null) {
error3(node.getId(), "T" + name);
}
elemTypes.put(node, "T" + name);
if (node.getElemName() != null) {
altsElemNameTypes.put(currentAlt + "." + node.getElemName().getText(), "T" + name);
}
String type_name = name;
if (node.getUnOp() instanceof AStarUnOp || node.getUnOp() instanceof AQMarkUnOp) {
type_name += "?";
}
altsElemTypes.put(currentAlt + "." + nameOfElem, "T" + type_name);
} else {
elemTypes.put(node, "P" + name);
if (node.getElemName() != null) {
altsElemNameTypes.put(currentAlt + "." + node.getElemName().getText(), "P" + name);
}
String type_name = name;
if (node.getUnOp() instanceof AStarUnOp || node.getUnOp() instanceof AQMarkUnOp) {
type_name += "?";
}
altsElemTypes.put(currentAlt + "." + nameOfElem, "P" + type_name);
}
}
}
}
);
}
public static String name(String s) {
StringBuffer result = new StringBuffer();
boolean upcase = true;
int length = s.length();
char c;
for (int i = 0; i < length; i++) {
c = s.charAt(i);
switch (c) {
case '_':
upcase = true;
break;
case '$':
result.append(c);
upcase = true;
break;
default:
if (upcase) {
result.append(Character.toUpperCase(c));
upcase = false;
} else {
result.append(c);
}
break;
}
}
return result.toString();
}
public static String errorName(String s) {
StringBuffer result = new StringBuffer();
int length = s.length();
char c;
for (int i = 0; i < length; i++) {
c = s.charAt(i);
switch (c) {
case '_': {
result.append(' ');
}
break;
default: {
result.append(c);
}
break;
}
}
return result.toString();
}
public void reinit() {
names.clear();
elemTypes.clear();
}
private static void error(Token token, String name) {
throw new RuntimeException(
"[" + token.getLine() + "," + token.getPos() + "] " +
"Redefinition of " + name + ".");
}
private void error(String name) {
throw new RuntimeException(
"[" + lastLine + "," + lastPos + "] " +
"Redefinition of " + name + ".");
}
private static void error2(Token token, String name) {
throw new RuntimeException(
"[" + token.getLine() + "," + token.getPos() + "] " +
name + " undefined.");
}
private static void error3(Token token, String name) {
throw new RuntimeException(
"[" + token.getLine() + "," + token.getPos() + "] " +
name + " is ignored.");
}
private static void error4(Token token, String name) {
throw new RuntimeException(
"[" + token.getLine() + "," + token.getPos() + "] " +
"ambiguous " + name + ".");
}
private static void error5(Token token) {
throw new RuntimeException(
"[" + token.getLine() + "," + token.getPos() + "] " +
"class is an invalid element name.");
}
@Override
public String toString() {
StringBuffer s = new StringBuffer();
String nl = System.getProperty("line.separator");
s.append("Helpers:");
s.append(nl);
s.append(helpers);
s.append(nl);
s.append("States:");
s.append(nl);
s.append(states);
s.append(nl);
s.append("Tokens:");
s.append(nl);
s.append(tokens);
s.append(nl);
s.append("Ignored Tokens:");
s.append(nl);
s.append(ignTokens);
s.append(nl);
s.append("Productions:");
s.append(nl);
s.append(prods);
s.append(nl);
s.append("Alternatives:");
s.append(nl);
s.append(alts);
s.append(nl);
s.append("Elements:");
s.append(nl);
s.append(elems);
s.append(nl);
return s.toString();
}
}