1
/*******************************************************************************
2
* Copyright (c) 2006, 2008 IBM Corporation and others.
3
* All rights reserved. This program and the accompanying materials
4
* are made available under the terms of the Eclipse Public License v1.0
5
* which accompanies this distribution, and is available at
6
* http://www.eclipse.org/legal/epl-v10.html
9
* IBM Corporation - initial API and implementation
10
*******************************************************************************/
11
package org.eclipse.cdt.internal.core.dom.lrparser.symboltable;
13
import java.util.ArrayList;
14
import java.util.LinkedList;
15
import java.util.List;
17
import org.eclipse.cdt.core.dom.ast.IBinding;
21
* Used to compute binding resolution during the parse.
23
* Imperative style symbol table with destructive update.
25
* Consists of two data structures, a hash table for fast lookup
26
* of bindings given their names, and a stack used to keep track
32
public class CImperativeSymbolTable {
34
private static final int TABLE_SIZE = 256;
36
private Bucket[] table = new Bucket[TABLE_SIZE];
38
private LinkedList<SymbolScope> scopeStack = new LinkedList<SymbolScope>();
43
* Represents a scope in the C language.
45
private static class SymbolScope {
48
* List of buckets that have been modified in the current scope.
49
* When the scope is closed these buckets are popped, returning the
50
* symbol table to the state it was in before the scope was opened.
52
List<Integer> modifiedBuckets = new ArrayList<Integer>();
57
* A bucket object used to hold elements in the hash table.
59
private static class Bucket {
65
Bucket(Bucket next, CNamespace namespace, String key, IBinding binding) {
67
this.namespace = namespace;
68
this.binding = binding;
74
public CImperativeSymbolTable() {
75
openScope(); // open the global scope
76
// TODO populate the global scope with built-ins
81
* Hashes a key into an index in the hash table.
83
private int index(String key) {
84
return Math.abs(key.hashCode() % TABLE_SIZE);
89
* Adds a binding to the symbol table in the current scope.
91
* @param mask A bit mask used to identify the namespace of the identifier.
93
public void put(CNamespace namespace, String ident, IBinding b) {
94
int index = index(ident);
95
table[index] = new Bucket(table[index], namespace, ident, b);
97
SymbolScope scope = scopeStack.getLast();
98
scope.modifiedBuckets.add(index);
103
* Returns the binding associated with the given identifier, or
104
* null if there is none.
106
* @param mask A bit mask used to identify the namespace of the identifier.
108
public IBinding get(CNamespace namespace, String ident) {
109
Bucket b = table[index(ident)];
111
if(namespace == b.namespace && ident.equals(b.key))
120
* Opens a new inner scope for identifiers.
122
* If an identifier is added that already exists in an outer scope
123
* then it will be shadowed.
125
public void openScope() {
126
scopeStack.add(new SymbolScope());
131
* Remove all the symbols defined in the scope that is being closed.
133
* @param scope An IScope object that will be used to represent this scope.
134
* @throws SymbolTableException If the global scope has already been closed or if bindingScope is null.
136
public void closeScope() {
137
SymbolScope poppedScope = scopeStack.removeLast(); // pop the scopeStack
139
// pop each bucket that was modified in the scope
140
for(int index : poppedScope.modifiedBuckets)
141
table[index] = table[index].next;
145
@SuppressWarnings("nls")
147
public String toString() {
148
StringBuilder buff = new StringBuilder('[');
149
for(Bucket b : table) {
151
buff.append('<').append(b.key).append(": ").append(b.binding).append(">, ");
155
return buff.append(']').toString();