Создание таблицы символов на основе грамматики

Я пытаюсь создать таблицу символов из моей грамматики (выполняется с помощью antlr) с помощью eclipse. Однако я не знаю, с чего начать. Думаю, я где-то читал, что для этого вам понадобятся парсер и лексер, сгенерированные antlr. Кто-нибудь знает простой пример, чтобы я мог понять, как он работает, пожалуйста?


person Exia0890    schedule 23.03.2013    source источник
comment
Прочтите любой стандартный текст о таблицах символов компилятора. После этого это просто (пачка) пота. ANTLR не предлагает вам никакой конкретной помощи; это генератор парсеров, и он действительно хорошо работает, а затем останавливается.   -  person Ira Baxter    schedule 24.03.2013
comment
Да, сейчас проверяю их. Похоже, вы можете выполнить getTree в лексере, сгенерированном antlr, и поработать над ним.   -  person Exia0890    schedule 28.03.2013


Ответы (1)


Таблица символов - это просто версионная карта идентификаторов и значений. Это одно из решений, использующее push и pop областей в качестве механизма управления версиями - push область при входе в правило, определяющее область, и pop при выходе.

package net.certiv.metal.symbol;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

import net.certiv.metal.types.ScopeType;
import net.certiv.metal.util.Strings;

public class Scope {

    public final int genId;

    public ScopeType type;
    public Scope enclosingScope;
    protected Map<String, Symbol> symbolMap = new LinkedHashMap<String, Symbol>();

    public Scope(ScopeType type, final int genId, Scope enclosingScope) {
        this.type = type;
        this.genId = genId;
        this.enclosingScope = enclosingScope;
    }

    /** 
     * Define a new variable in the current scope 
     * This is the entry point for adding new variables
     */
    public void define(String name, ArrayList<String> parameters) {
        String params = Strings.asString(parameters, true, ".");
        Symbol symbol = new Symbol(null, name + params, null);
        define(symbol);
    }

    /** Define a symbol in the current scope */
    private void define(Symbol symbol) {
        symbol.setScope(this);
        symbolMap.put(symbol.name, symbol);
    }

    /**
     * Look up the symbol name in this scope and, if not found, 
     * progressively search the enclosing scopes. 
     * Return null if not found in any applicable scope.
     */
    private Symbol resolve(String name) {
        Symbol symbol = symbolMap.get(name);
        if (symbol != null) return symbol;
        if (enclosingScope != null) return enclosingScope.resolve(name);
        return null; // not found
    }
    /**
     * Lookup a variable starting in the current scope.
     * This is the entry point for lookups
     */
    public Symbol resolve(String name, ArrayList<String> parameters) {
        String params = Strings.asString(parameters, true, ".");
        return resolve(name + params);
    }

    /** Where to look next for symbols */
    public Scope enclosingScope() {
        return enclosingScope;
    }

    public String toString() {
        return symbolMap.keySet().toString();
    }
}


package net.certiv.metal.types;

public enum ScopeType {
    GLOBAL,
    LOCAL;
}



package net.certiv.metal.symbol;

import net.certiv.metal.converter.BaseDescriptor;
import net.certiv.metal.types.ValueType;

public class Symbol {

    protected Scope scope; // the owning scope
    protected BaseDescriptor descriptor;
    protected String name;
    protected ValueType type;

    public Symbol(BaseDescriptor descriptor, String name, ValueType type) {
        this.descriptor = descriptor;
        this.name = name;
        this.type = type;
    }

    public BaseDescriptor getDescriptor() {
        return descriptor;
    }

    public String getName() {
        return name;
    }

    public ValueType getType() {
        return type;
    }

    public void setScope(Scope scope) {
        this.scope = scope;
    }

    public Scope getScope() {
        return scope;
    }

    public int genId() {
        return scope.genId;
    }

    public String toString() {
        if (type != null) return '<' + getName() + ":" + type + '>';
        return getName();
    }
}

package net.certiv.metal.symbol;

import java.util.ArrayList;
import java.util.Stack;

import net.certiv.metal.types.ScopeType;
import net.certiv.metal.util.Log;

public class SymbolTable {

    protected Stack<Scope> scopeStack;
    protected ArrayList<Scope> allScopes;
    protected int genId;

    public SymbolTable() {
        init();
    }

    protected void init() {
        scopeStack = new Stack<>();
        allScopes = new ArrayList<>();
        genId = 0;

        Scope globals = new Scope(ScopeType.GLOBAL, nextGenId(), null);
        scopeStack.push(globals);
        allScopes.add(globals);
    }

    public Scope pushScope() {
        Scope enclosingScope = scopeStack.peek();
        Scope scope = new Scope(ScopeType.LOCAL, nextGenId(), enclosingScope);
        scopeStack.push(scope);
        allScopes.add(scope);
        return scope;
    }

    public void popScope() {
        scopeStack.pop();
    }

    public Scope currentScope() {
        if (scopeStack.size() > 0) {
            return scopeStack.peek();
        }
        Log.error(this, "Unbalanced scope stack.");
        return allScopes.get(0);
    }

    public Scope getScope(int genId) {
        for (Scope scope : scopeStack) {
            if (scope.genId == genId) return scope;
        }
        return null;
    }

    private int nextGenId() {
        genId++;
        return genId;
    }

    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Scope scope : scopeStack.subList(0, scopeStack.size() - 1)) {
            sb.append(scope.toString());
        }
        return sb.toString();
    }
}
person GRosenberg    schedule 24.03.2013
comment
Таблица символов на самом деле является отображением каждого экземпляра идентификатора на дескриптор экземпляра типа для этого идентификатора. Области видимости - это способ организовать отображение символов в одной части кода на известные объявления символов в области. Этот ответ верен простым способом: многие старые языки могут обрабатываться простым стеком областей видимости. Более современные языки с пространствами имен и обобщениями не так просты, хотя идея карты остается. - person Ira Baxter; 24.03.2013
comment
Не уверен, что вы читаете слишком быстро или что, но ответ вполне правильный в том виде, в котором он представлен. Код представлен как одно из решений для иллюстрации механизмов работы с таблицей символов, что является прямым ответом на вопрос ОП. Любые экзистенциальные квалификации могут быть реализованы при отображении идентификаторов в значения, но это не было элементом вопроса OP. Кроме того, существуют языки без типа / с одним типом, что, согласно грамматике OP, может иметь место для OP. Пространства имен и обобщенные типы, которые обрабатываются формами управления версиями, не участвуют в грамматике OP. - person GRosenberg; 25.03.2013
comment
Я не жаловался на ваше решение как на набросок (примечание: никакого звонка!), Просто заметил, что для построения таблиц символов для реальных языков, вероятно, потребуется больше, чем это. Может, его язык прост. Ему лучше решить, прежде чем он приступит к реализации, что было моей первоначальной точкой зрения о подробном чтении таблиц символов, прежде чем спешить что-то делать. - person Ira Baxter; 25.03.2013
comment
Извините за поздний ответ, спасибо вам обоим за ответы. @GRosenberg, спасибо за ваш код, я все еще работаю над ним, чтобы понять его и посмотреть, будет ли он работать с моей грамматикой. Однако есть несколько импортированных классов, откуда я не мог видеть :( util.Strings; util.Log; ValueType;). - person Exia0890; 28.03.2013
comment
Strings.asString применяет правило (что вы хотите) для нормализации представления имени переменной. Например, преобразование сложной схемы именования переменных в более простое строковое представление в кодировке свойств (a.b.c) с соответствующей уникальностью. ValueType может быть простым перечислением, определяющим формальный тип переменной. BaseDescriptor может быть классом, содержащим любые расширенные данные, которые вы хотите связать с переменной. - person GRosenberg; 29.03.2013
comment
Если ответ оказался полезным, отметьте его как принятый. - person GRosenberg; 14.04.2013