package edu.montana.cs.fafnir.cs550.hw2;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
final class Alphabet {
interface Namespace {
int TERMINAL = 1, NONTERMINAL = 2, LAMBDA = 3;
}
private HashMap terminals, nonterminals;
private Lambda lambda;
private Nonterminal start;
Alphabet() {
terminals = new HashMap();
nonterminals = new HashMap();
lambda = new Lambda();
start = null;
}
Iterator getIterator(int namespace) throws FFException {
if (namespace == Namespace.LAMBDA) {
return Collections.singletonList(lambda).iterator();
} else if (namespace == Namespace.TERMINAL) {
return terminals.values().iterator();
} else if (namespace == Namespace.NONTERMINAL) {
return nonterminals.values().iterator();
} else {
throw new FFException("invalid namespace");
}
}
Symbol getStart() {
return start;
}
Lambda lambda() {
return lambda;
}
Symbol lookupConstructively(String name, int namespace) throws FFException {
if (namespace == Namespace.LAMBDA) {
if (name.equals("lambda")) {
return lambda;
} else {
throw new FFException("attempted to find non-lambda in lambda namespace");
}
} else if (namespace == Namespace.TERMINAL) {
Object rawSymbol = terminals.get(name);
if (rawSymbol != null) {
return (Symbol) rawSymbol;
} else {
Symbol s = new Terminal(name);
terminals.put(name, s);
return s;
}
} else if (namespace == Namespace.NONTERMINAL) {
Object rawSymbol = nonterminals.get(name);
if (rawSymbol != null) {
return (Symbol) rawSymbol;
} else {
Symbol s = new Nonterminal(name);
nonterminals.put(name, s);
return s;
}
} else {
throw new FFException("invalid symbol type; neither lambda, terminal, or nonterminal");
}
}
Symbol lookup(String name, int namespace) throws FFException {
if (namespace == Namespace.LAMBDA) {
if (name.equals("lambda")) {
return lambda;
} else {
throw new FFException("attempted to find non-lambda in lambda namespace");
}
} else if (namespace == Namespace.TERMINAL) {
Object rawSymbol = terminals.get(name);
if (rawSymbol != null) {
return (Symbol) rawSymbol;
} else {
throw new FFException("could not find the terminal \"" + name + "\"");
}
} else if (namespace == Namespace.NONTERMINAL) {
Object rawSymbol = nonterminals.get(name);
if (rawSymbol != null) {
return (Symbol) rawSymbol;
} else {
throw new FFException("could not find the nonterminal \"" + name + "\"");
}
} else {
throw new FFException("invalid symbol type; neither lambda, terminal, or nonterminal");
}
}
void makeStart(Nonterminal s) throws FFException {
if (s instanceof Nonterminal) {
if (start != null)
start.setIsStart(false);
start = s;
start.setIsStart(true);
} else {
throw new FFException("a symbol can not be start if it isn't a nonterminal");
}
}
public String toString() {
StringBuffer result = new StringBuffer("alphabet:\n\n");
result.append(lambda.toString() + '\n');
for (Iterator i = terminals.values().iterator(); i.hasNext(); ) {
result.append(((Terminal)i.next()).toString() + '\n');
}
for (Iterator i = nonterminals.values().iterator(); i.hasNext(); ) {
Nonterminal non = (Nonterminal)i.next();
if (non == start)
result.append(non.toString() + " START\n");
else
result.append(non.toString() + '\n');
}
return result.toString();
}
}