blob: 74e784810a94776f81d2a4dcbf1137a62b01a585 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.lrparser.c99.action.deprecated;
import java.util.LinkedList;
import org.eclipse.cdt.core.dom.lrparser.action.ITokenStream;
import org.eclipse.cdt.core.parser.util.DebugUtil;
import org.eclipse.cdt.internal.core.dom.lrparser.symboltable.TypedefSymbolTable;
import lpg.lpgjavaruntime.IToken;
/**
* A simple set of trial and undo actions that just keep track
* of typedef names. This information is then fed back to the parser
* in order to disambiguate certain parser grammar rules.
*
* The command design pattern is used to implement undo actions.
*
* @author Mike Kucera
*/
public class C99TypedefTrackerParserAction {
private static final boolean DEBUG = true;
// provides limited access to the token stream
private final ITokenStream parser;
// The symbolTable currently in use
private TypedefSymbolTable symbolTable = TypedefSymbolTable.EMPTY_TABLE;
// A stack that keeps track of scopes in the symbol table, used to "close" scopes and to undo the opening of scopes
private final LinkedList<TypedefSymbolTable> symbolTableScopeStack = new LinkedList<>();
// keeps track of nested declarations
private final LinkedList<DeclaratorFrame> declarationStack = new LinkedList<>();
// "For every action there is an equal and opposite reaction." - Newton's third law
private final LinkedList<IUndoAction> undoStack = new LinkedList<>();
/**
* A command object that provides undo functionality.
*/
private interface IUndoAction {
void undo();
}
/**
* Undoes the last fired action.
*/
public void undo() {
undoStack.removeLast().undo();
}
public C99TypedefTrackerParserAction(ITokenStream parser) {
this.parser = parser;
}
/**
* Lexer feedback hack, used by the parser to identify typedefname tokens.
*/
public boolean isTypedef(String ident) {
return symbolTable.contains(ident);
}
/**
* Methods used by tests, package local access.
*/
TypedefSymbolTable getSymbolTable() {
return symbolTable;
}
int undoStackSize() {
return undoStack.size();
}
LinkedList<DeclaratorFrame> getDeclarationStack() {
return declarationStack;
}
/**
* Called from the grammar file in places where a scope is created.
*
* Scopes are created by compound statements, however special care
* must also be taken with for loops because they may contain
* declarations.
*
* TODO: scope object now need to be handled explicitly
*/
public void openSymbolScope() {
if (DEBUG)
DebugUtil.printMethodTrace();
symbolTableScopeStack.add(symbolTable);
undoStack.add(new IUndoAction() {
@Override
public void undo() {
if (DEBUG)
DebugUtil.printMethodTrace();
symbolTable = symbolTableScopeStack.removeLast();
}
});
}
public void closeSymbolScope() {
if (DEBUG)
DebugUtil.printMethodTrace();
final TypedefSymbolTable undoTable = symbolTable;
symbolTable = symbolTableScopeStack.removeLast(); // close the scope
undoStack.add(new IUndoAction() {
@Override
public void undo() {
if (DEBUG)
DebugUtil.printMethodTrace();
symbolTableScopeStack.add(symbolTable);
symbolTable = undoTable;
}
});
}
/**
* Called from the grammar before a declaration is about to be reduced.
*/
public void openDeclarationScope() {
if (DEBUG)
DebugUtil.printMethodTrace();
declarationStack.add(new DeclaratorFrame());
undoStack.add(new IUndoAction() {
@Override
public void undo() {
if (DEBUG)
DebugUtil.printMethodTrace();
declarationStack.removeLast();
}
});
}
public void closeDeclarationScope() {
if (DEBUG)
DebugUtil.printMethodTrace();
final DeclaratorFrame undoFrame = declarationStack.removeLast();
undoStack.add(new IUndoAction() {
@Override
public void undo() {
if (DEBUG)
DebugUtil.printMethodTrace();
declarationStack.add(undoFrame);
}
});
}
public void consumeFunctionDefinition() {
if (DEBUG)
DebugUtil.printMethodTrace();
final DeclaratorFrame frame = declarationStack.removeLast();
final TypedefSymbolTable undoTable = symbolTable;
symbolTable = symbolTableScopeStack.removeLast();
undoStack.add(new IUndoAction() {
@Override
public void undo() {
if (DEBUG)
DebugUtil.printMethodTrace();
symbolTableScopeStack.add(symbolTable);
symbolTable = undoTable;
declarationStack.add(frame);
}
});
}
public void consumeDeclSpecToken() {
if (DEBUG)
DebugUtil.printMethodTrace();
IToken token = parser.getRightIToken();
final int kind = token.getKind();
// creates a DeclSpec if there isn't one already
DeclaratorFrame frame = declarationStack.getLast();
final DeclSpec declSpec = frame.getDeclSpec();
declSpec.add(kind);
undoStack.add(new IUndoAction() {
@Override
public void undo() {
if (DEBUG)
DebugUtil.printMethodTrace();
declSpec.remove(kind);
}
});
}
public void consumeDirectDeclaratorIdentifier() {
if (DEBUG)
DebugUtil.printMethodTrace();
final DeclaratorFrame frame = declarationStack.getLast();
frame.setDeclaratorName(parser.getRightIToken());
undoStack.add(new IUndoAction() {
@Override
public void undo() {
if (DEBUG)
DebugUtil.printMethodTrace();
frame.setDeclaratorName(null);
}
});
}
public void consumeDeclaratorComplete() {
if (DEBUG)
DebugUtil.printMethodTrace();
final DeclaratorFrame frame = declarationStack.getLast();
IToken token = frame.getDeclaratorName();
DeclSpec declSpec = frame.getDeclSpec();
String ident = (token == null) ? null : token.toString();
//System.out.println("declarator complete: " + ident);
final TypedefSymbolTable oldTable = symbolTable;
if (declSpec.isTypedef()) {
//System.out.println("adding typedef: " + ident);
symbolTable = symbolTable.add(ident);
}
declarationStack.removeLast();
declarationStack.add(new DeclaratorFrame(frame.getDeclSpec())); // reset the declarator
undoStack.add(new IUndoAction() {
@Override
public void undo() {
if (DEBUG)
DebugUtil.printMethodTrace();
declarationStack.removeLast();
declarationStack.add(frame);
symbolTable = oldTable;
}
});
}
public void consumeDeclaratorCompleteParameter() {
if (DEBUG)
DebugUtil.printMethodTrace();
final DeclaratorFrame frame = declarationStack.removeLast();
//declarationStack.getLast().addNestedDeclaration(parameterBinding);
// parameter declarations can only have one declarator, so don't reset
//declarationStack.add(new DeclaratorFrame()); // reset
undoStack.add(new IUndoAction() {
@Override
public void undo() {
if (DEBUG)
DebugUtil.printMethodTrace();
//declarationStack.removeLast();
//declarationStack.getLast().removeLastNestedDeclaration();
declarationStack.add(frame);
}
});
}
/**
* This is a special case for the rule:
* parameter_declaration ::= declaration_specifiers
*
* In this case there is no declarator at all
*
* TODO: creating bindings that have no identifier seems really dumb,
* why does it need to be done? Why not just have a null binding or
* for that matter don't even have a name node
*
*/
public void consumeParameterDeclarationWithoutDeclarator() {
if (DEBUG)
DebugUtil.printMethodTrace();
final DeclaratorFrame frame = declarationStack.removeLast();
undoStack.add(new IUndoAction() {
@Override
public void undo() {
if (DEBUG)
DebugUtil.printMethodTrace();
declarationStack.add(frame);
}
});
}
public void consumeDeclaratorCompleteField() {
if (DEBUG)
DebugUtil.printMethodTrace();
final DeclaratorFrame frame = declarationStack.removeLast();
declarationStack.add(new DeclaratorFrame(frame.getDeclSpec())); // reset the declarator
undoStack.add(new IUndoAction() {
@Override
public void undo() {
if (DEBUG)
DebugUtil.printMethodTrace();
declarationStack.removeLast();
declarationStack.add(frame);
}
});
}
/**
* An abstract declarator used as part of an expression, eg) a cast.
* Only need the type.
*
* TODO: this isn't enough, I need a binding for the abstract declarator
* what I really need is a consumeDeclaratorCompleteTypeId similar to above
*/
public void consumeTypeId() {
if (DEBUG)
DebugUtil.printMethodTrace();
final DeclaratorFrame frame = declarationStack.removeLast();
undoStack.add(new IUndoAction() {
@Override
public void undo() {
if (DEBUG)
DebugUtil.printMethodTrace();
declarationStack.add(frame);
}
});
}
}