Support function declarations in the definitions of other functions.
As part of this, function declarations are no longer scoped (this is permitted
by the C standard, as it turns out.) So code like:
void foo() { void bar(); }
void bat() { bar(); }
Compiles correctly; the declaration of bar() in foo() is still available in the
definition of bar().
Fixes issue #129.
This commit is contained in:
30
decl.cpp
30
decl.cpp
@@ -535,8 +535,6 @@ Declaration::GetVariableDeclarations() const {
|
|||||||
std::vector<VariableDeclaration> vars;
|
std::vector<VariableDeclaration> vars;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < declarators.size(); ++i) {
|
for (unsigned int i = 0; i < declarators.size(); ++i) {
|
||||||
if (declarators[i] == NULL)
|
|
||||||
continue;
|
|
||||||
Declarator *decl = declarators[i];
|
Declarator *decl = declarators[i];
|
||||||
if (decl == NULL)
|
if (decl == NULL)
|
||||||
// Ignore earlier errors
|
// Ignore earlier errors
|
||||||
@@ -545,11 +543,7 @@ Declaration::GetVariableDeclarations() const {
|
|||||||
Symbol *sym = decl->GetSymbol();
|
Symbol *sym = decl->GetSymbol();
|
||||||
sym->type = sym->type->ResolveUnboundVariability(Type::Varying);
|
sym->type = sym->type->ResolveUnboundVariability(Type::Varying);
|
||||||
|
|
||||||
if (dynamic_cast<const FunctionType *>(sym->type) != NULL) {
|
if (dynamic_cast<const FunctionType *>(sym->type) == NULL) {
|
||||||
// function declaration
|
|
||||||
m->symbolTable->AddFunction(sym);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m->symbolTable->AddVariable(sym);
|
m->symbolTable->AddVariable(sym);
|
||||||
vars.push_back(VariableDeclaration(sym, decl->initExpr));
|
vars.push_back(VariableDeclaration(sym, decl->initExpr));
|
||||||
}
|
}
|
||||||
@@ -558,6 +552,28 @@ Declaration::GetVariableDeclarations() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Declaration::DeclareFunctions() {
|
||||||
|
Assert(declSpecs->storageClass != SC_TYPEDEF);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < declarators.size(); ++i) {
|
||||||
|
Declarator *decl = declarators[i];
|
||||||
|
if (decl == NULL)
|
||||||
|
// Ignore earlier errors
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Symbol *sym = decl->GetSymbol();
|
||||||
|
sym->type = sym->type->ResolveUnboundVariability(Type::Varying);
|
||||||
|
|
||||||
|
if (dynamic_cast<const FunctionType *>(sym->type) == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool isInline = (declSpecs->typeQualifiers & TYPEQUAL_INLINE);
|
||||||
|
m->AddFunctionDeclaration(sym, isInline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Declaration::Print(int indent) const {
|
Declaration::Print(int indent) const {
|
||||||
printf("%*cDeclaration: specs [", indent, ' ');
|
printf("%*cDeclaration: specs [", indent, ' ');
|
||||||
|
|||||||
4
decl.h
4
decl.h
@@ -210,6 +210,10 @@ public:
|
|||||||
Declarator representation.) */
|
Declarator representation.) */
|
||||||
std::vector<VariableDeclaration> GetVariableDeclarations() const;
|
std::vector<VariableDeclaration> GetVariableDeclarations() const;
|
||||||
|
|
||||||
|
/** For any function declarations in the Declaration, add the
|
||||||
|
declaration to the module. */
|
||||||
|
void DeclareFunctions();
|
||||||
|
|
||||||
DeclSpecs *declSpecs;
|
DeclSpecs *declSpecs;
|
||||||
std::vector<Declarator *> declarators;
|
std::vector<Declarator *> declarators;
|
||||||
};
|
};
|
||||||
|
|||||||
1
parse.yy
1
parse.yy
@@ -494,6 +494,7 @@ declaration_statement
|
|||||||
$$ = NULL;
|
$$ = NULL;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
$1->DeclareFunctions();
|
||||||
std::vector<VariableDeclaration> vars = $1->GetVariableDeclarations();
|
std::vector<VariableDeclaration> vars = $1->GetVariableDeclarations();
|
||||||
$$ = new DeclStmt(vars, @1);
|
$$ = new DeclStmt(vars, @1);
|
||||||
}
|
}
|
||||||
|
|||||||
73
sym.cpp
73
sym.cpp
@@ -72,8 +72,7 @@ SymbolTable::SymbolTable() {
|
|||||||
|
|
||||||
SymbolTable::~SymbolTable() {
|
SymbolTable::~SymbolTable() {
|
||||||
// Otherwise we have mismatched push/pop scopes
|
// Otherwise we have mismatched push/pop scopes
|
||||||
Assert(variables.size() == 1 && functions.size() == 1 &&
|
Assert(variables.size() == 1 && types.size() == 1);
|
||||||
types.size() == 1);
|
|
||||||
PopScope();
|
PopScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +80,6 @@ SymbolTable::~SymbolTable() {
|
|||||||
void
|
void
|
||||||
SymbolTable::PushScope() {
|
SymbolTable::PushScope() {
|
||||||
variables.push_back(new SymbolMapType);
|
variables.push_back(new SymbolMapType);
|
||||||
functions.push_back(new FunctionMapType);
|
|
||||||
types.push_back(new TypeMapType);
|
types.push_back(new TypeMapType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,10 +90,6 @@ SymbolTable::PopScope() {
|
|||||||
delete variables.back();
|
delete variables.back();
|
||||||
variables.pop_back();
|
variables.pop_back();
|
||||||
|
|
||||||
Assert(functions.size() > 1);
|
|
||||||
delete functions.back();
|
|
||||||
functions.pop_back();
|
|
||||||
|
|
||||||
Assert(types.size() > 1);
|
Assert(types.size() > 1);
|
||||||
delete types.back();
|
delete types.back();
|
||||||
types.pop_back();
|
types.pop_back();
|
||||||
@@ -160,7 +154,7 @@ SymbolTable::AddFunction(Symbol *symbol) {
|
|||||||
// the symbol table
|
// the symbol table
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::vector<Symbol *> &funOverloads = (*functions.back())[symbol->name];
|
std::vector<Symbol *> &funOverloads = functions[symbol->name];
|
||||||
funOverloads.push_back(symbol);
|
funOverloads.push_back(symbol);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -168,17 +162,14 @@ SymbolTable::AddFunction(Symbol *symbol) {
|
|||||||
|
|
||||||
bool
|
bool
|
||||||
SymbolTable::LookupFunction(const char *name, std::vector<Symbol *> *matches) {
|
SymbolTable::LookupFunction(const char *name, std::vector<Symbol *> *matches) {
|
||||||
for (int i = (int)functions.size() - 1; i >= 0; --i) {
|
FunctionMapType::iterator iter = functions.find(name);
|
||||||
FunctionMapType &fm = *(functions[i]);
|
if (iter != functions.end()) {
|
||||||
FunctionMapType::iterator iter = fm.find(name);
|
if (matches == NULL)
|
||||||
if (iter != fm.end()) {
|
return true;
|
||||||
if (matches == NULL)
|
else {
|
||||||
return true;
|
const std::vector<Symbol *> &funcs = iter->second;
|
||||||
else {
|
for (int j = 0; j < (int)funcs.size(); ++j)
|
||||||
const std::vector<Symbol *> &funcs = iter->second;
|
matches->push_back(funcs[j]);
|
||||||
for (int j = 0; j < (int)funcs.size(); ++j)
|
|
||||||
matches->push_back(funcs[j]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return matches ? (matches->size() > 0) : false;
|
return matches ? (matches->size() > 0) : false;
|
||||||
@@ -187,15 +178,12 @@ SymbolTable::LookupFunction(const char *name, std::vector<Symbol *> *matches) {
|
|||||||
|
|
||||||
Symbol *
|
Symbol *
|
||||||
SymbolTable::LookupFunction(const char *name, const FunctionType *type) {
|
SymbolTable::LookupFunction(const char *name, const FunctionType *type) {
|
||||||
for (int i = (int)functions.size() - 1; i >= 0; --i) {
|
FunctionMapType::iterator iter = functions.find(name);
|
||||||
FunctionMapType &fm = *(functions[i]);
|
if (iter != functions.end()) {
|
||||||
FunctionMapType::iterator iter = fm.find(name);
|
std::vector<Symbol *> funcs = iter->second;
|
||||||
if (iter != fm.end()) {
|
for (int j = 0; j < (int)funcs.size(); ++j) {
|
||||||
std::vector<Symbol *> funcs = iter->second;
|
if (Type::Equal(funcs[j]->type, type))
|
||||||
for (int j = 0; j < (int)funcs.size(); ++j) {
|
return funcs[j];
|
||||||
if (Type::Equal(funcs[j]->type, type))
|
|
||||||
return funcs[j];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -261,14 +249,11 @@ SymbolTable::ClosestVariableOrFunctionMatch(const char *str) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < (int)functions.size(); ++i) {
|
FunctionMapType::const_iterator iter;
|
||||||
const FunctionMapType &fm = *(functions[i]);
|
for (iter = functions.begin(); iter != functions.end(); ++iter) {
|
||||||
FunctionMapType::const_iterator iter;
|
int dist = StringEditDistance(str, iter->first, maxDelta+1);
|
||||||
for (iter = fm.begin(); iter != fm.end(); ++iter) {
|
if (dist <= maxDelta)
|
||||||
int dist = StringEditDistance(str, iter->first, maxDelta+1);
|
matches[dist].push_back(iter->first);
|
||||||
if (dist <= maxDelta)
|
|
||||||
matches[dist].push_back(iter->first);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, return the first entry of matches[] that is non-empty, if any.
|
// Now, return the first entry of matches[] that is non-empty, if any.
|
||||||
@@ -346,15 +331,13 @@ SymbolTable::Print() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Functions:\n----------------\n");
|
fprintf(stderr, "Functions:\n----------------\n");
|
||||||
for (int i = 0; i < (int)functions.size(); ++i) {
|
FunctionMapType::iterator fiter = functions.begin();
|
||||||
FunctionMapType::iterator fiter = functions[i]->begin();
|
while (fiter != functions.end()) {
|
||||||
while (fiter != functions[i]->end()) {
|
fprintf(stderr, "%s\n", fiter->first.c_str());
|
||||||
fprintf(stderr, "%s\n", fiter->first.c_str());
|
std::vector<Symbol *> &syms = fiter->second;
|
||||||
std::vector<Symbol *> &syms = fiter->second;
|
for (unsigned int j = 0; j < syms.size(); ++j)
|
||||||
for (unsigned int j = 0; j < syms.size(); ++j)
|
fprintf(stderr, " %s\n", syms[j]->type->GetString().c_str());
|
||||||
fprintf(stderr, " %s\n", syms[j]->type->GetString().c_str());
|
++fiter;
|
||||||
++fiter;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
depth = 0;
|
depth = 0;
|
||||||
|
|||||||
26
sym.h
26
sym.h
@@ -257,12 +257,13 @@ private:
|
|||||||
typedef std::map<std::string, Symbol *> SymbolMapType;
|
typedef std::map<std::string, Symbol *> SymbolMapType;
|
||||||
std::vector<SymbolMapType *> variables;
|
std::vector<SymbolMapType *> variables;
|
||||||
|
|
||||||
/** Function declarations are also scoped., A STL \c vector is used to
|
/** Function declarations are *not* scoped. (C99, for example, allows
|
||||||
store the function symbols for a given name since, due to function
|
an implementation to maintain function declarations in a single
|
||||||
overloading, a name can have multiple function symbols associated
|
namespace.) A STL \c vector is used to store the function symbols
|
||||||
with it. */
|
for a given name since, due to function overloading, a name can
|
||||||
|
have multiple function symbols associated with it. */
|
||||||
typedef std::map<std::string, std::vector<Symbol *> > FunctionMapType;
|
typedef std::map<std::string, std::vector<Symbol *> > FunctionMapType;
|
||||||
std::vector<FunctionMapType *> functions;
|
FunctionMapType functions;
|
||||||
|
|
||||||
/** Type definitions can also be scoped. A new \c TypeMapType
|
/** Type definitions can also be scoped. A new \c TypeMapType
|
||||||
is added to the back of the \c types \c vector each time a new scope
|
is added to the back of the \c types \c vector each time a new scope
|
||||||
@@ -278,15 +279,12 @@ SymbolTable::GetMatchingFunctions(Predicate pred,
|
|||||||
std::vector<Symbol *> *matches) const {
|
std::vector<Symbol *> *matches) const {
|
||||||
// Iterate through all function symbols and apply the given predicate.
|
// Iterate through all function symbols and apply the given predicate.
|
||||||
// If it returns true, add the Symbol * to the provided vector.
|
// If it returns true, add the Symbol * to the provided vector.
|
||||||
for (unsigned int i = 0; i < functions.size(); ++i) {
|
FunctionMapType::const_iterator iter;
|
||||||
FunctionMapType &fm = *(functions[i]);
|
for (iter = functions.begin(); iter != functions.end(); ++iter) {
|
||||||
FunctionMapType::const_iterator iter;
|
const std::vector<Symbol *> &syms = iter->second;
|
||||||
for (iter = fm.begin(); iter != fm.end(); ++iter) {
|
for (unsigned int j = 0; j < syms.size(); ++j) {
|
||||||
const std::vector<Symbol *> &syms = iter->second;
|
if (pred(syms[j]))
|
||||||
for (unsigned int j = 0; j < syms.size(); ++j) {
|
matches->push_back(syms[j]);
|
||||||
if (pred(syms[j]))
|
|
||||||
matches->push_back(syms[j]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user