/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.mmtk.harness.lang.parser;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import org.mmtk.harness.lang.Declaration;
import org.mmtk.harness.lang.type.Type;
/**
* Parser symbol table.
*
* Implements java-style scoping rules. Allocates variables to slots in a
* stack frame linearly and never re-uses slots.
*
* TODO - implement stack maps so that out-of-scope variables don't hold on
* to unreachable objects.
*/
public class SymbolTable {
/** These are illegal variable and method names */
public static final List<String> reservedWords = new ArrayList<String>();
static {
reservedWords.add("alloc");
reservedWords.add("assert");
reservedWords.add("else");
reservedWords.add("if");
reservedWords.add("int");
reservedWords.add("object");
reservedWords.add("print");
reservedWords.add("spawn");
reservedWords.add("while");
}
static final boolean TRACE = false;
/** The table of symbols */
private Map<String, Symbol> table = new HashMap<String,Symbol>();
/** The stack frame map */
private List<Declaration> stackMap = new ArrayList<Declaration>();
/** The next free stack frame slot */
private int nextLocation = 0;
/** The current syntactic scope level */
private int currentScope = 0;
int getCurrentScope() { return currentScope; }
int getFreeLocation() { return nextLocation++; }
/**
* Declare a new variable
*
* @param name Variable name
* @param type Variable type
*/
void declare(String name, Type type) {
if (reservedWords.contains(name))
throw new RuntimeException(name + " is a reserved word");
if (table.containsKey(name))
throw new RuntimeException("Symbol "+name+" already defined");
Symbol symbol = new Symbol(this,name,type);
table.put(name, symbol);
stackMap.add(new Declaration(symbol));
}
/**
* Is the given variable defined ?
* @param name
* @return
*/
boolean isDefined(String name) {
return table.containsKey(name);
}
/**
* Symbol table entry for the named variable
* @param name
* @return
*/
Symbol getSymbol(String name) {
return table.get(name);
}
/**
* Type of the named variable
* @param name
* @return
*/
Type getType(String name) {
return table.get(name).getType();
}
/**
* Stack frame location of the given variable
* @param name
* @return
*/
int getLocation(String name) {
Symbol symbol = table.get(name);
if (symbol == null) {
throw new RuntimeException(String.format("symbol \"%s\" not found",name));
}
return symbol.getLocation();
}
/**
* Return the symbol table as a list of declarations
* @return
*/
List<Declaration> declarations() {
return Collections.unmodifiableList(stackMap);
}
/**
* Enter an inner syntactic scope
*/
void pushScope() {
currentScope++;
}
/**
* Leave an inner syntactic scope, deleting all inner symbols
*/
void popScope() {
Set<Entry<String, Symbol>> entrySet = table.entrySet();
Iterator<Entry<String, Symbol>> iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Symbol> entry = iterator.next();
if (entry.getValue().getLevel() == currentScope)
iterator.remove();
}
currentScope--;
}
}