Fixed a problem with variable declarations in inner blocks giving errors. bug#82.

git-svn-id: http://picoc.googlecode.com/svn/trunk@470 21eae674-98b7-11dd-bd71-f92a316d2d60
This commit is contained in:
zik.saleeba 2010-07-24 16:07:56 +00:00
parent d87d25fede
commit 036f3efa8b
10 changed files with 63 additions and 24 deletions

View file

@ -767,7 +767,7 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack *
else if (Op == TokenAssign && TopInt == 0) else if (Op == TokenAssign && TopInt == 0)
{ {
/* assign a NULL pointer */ /* assign a NULL pointer */
HeapUnpopStack(sizeof(struct Value)); /* XXX - possible bug if lvalue is a temp value and takes more than sizeof(struct Value) */ HeapUnpopStack(sizeof(struct Value));
ExpressionAssign(Parser, BottomValue, TopValue, FALSE, NULL, 0, FALSE); ExpressionAssign(Parser, BottomValue, TopValue, FALSE, NULL, 0, FALSE);
ExpressionStackPushValueNode(Parser, StackTop, BottomValue); ExpressionStackPushValueNode(Parser, StackTop, BottomValue);
} }
@ -785,7 +785,7 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack *
else else
Pointer = (void *)((char *)Pointer - TopInt * Size); Pointer = (void *)((char *)Pointer - TopInt * Size);
HeapUnpopStack(sizeof(struct Value)); /* XXX - possible bug if lvalue is a temp value and takes more than sizeof(struct Value) */ HeapUnpopStack(sizeof(struct Value));
BottomValue->Val->Pointer = Pointer; BottomValue->Val->Pointer = Pointer;
ExpressionStackPushValueNode(Parser, StackTop, BottomValue); ExpressionStackPushValueNode(Parser, StackTop, BottomValue);
} }
@ -963,7 +963,7 @@ void ExpressionGetStructElement(struct ParseState *Parser, struct ExpressionStac
if (StructType->Base != TypeStruct && StructType->Base != TypeUnion) if (StructType->Base != TypeStruct && StructType->Base != TypeUnion)
ProgramFail(Parser, "can't use '%s' on something that's not a struct or union %s : it's a %t", (Token == TokenDot) ? "." : "->", (Token == TokenArrow) ? "pointer" : "", ParamVal->Typ); ProgramFail(Parser, "can't use '%s' on something that's not a struct or union %s : it's a %t", (Token == TokenDot) ? "." : "->", (Token == TokenArrow) ? "pointer" : "", ParamVal->Typ);
if (!TableGet(StructType->Members, Ident->Val->Identifier, &MemberValue)) if (!TableGet(StructType->Members, Ident->Val->Identifier, &MemberValue, NULL, NULL))
ProgramFail(Parser, "doesn't have a member called '%s'", Ident->Val->Identifier); ProgramFail(Parser, "doesn't have a member called '%s'", Ident->Val->Identifier);
/* pop the value - assume it'll still be there until we're done */ /* pop the value - assume it'll still be there until we're done */

4
lex.c
View file

@ -755,7 +755,7 @@ void LexHashIfdef(struct ParseState *Parser, int IfNot)
ProgramFail(Parser, "identifier expected"); ProgramFail(Parser, "identifier expected");
/* is the identifier defined? */ /* is the identifier defined? */
IsDefined = TableGet(&GlobalTable, IdentValue->Val->Identifier, &SavedValue); IsDefined = TableGet(&GlobalTable, IdentValue->Val->Identifier, &SavedValue, NULL, NULL);
if (Parser->HashIfEvaluateToLevel == Parser->HashIfLevel && ( (IsDefined && !IfNot) || (!IsDefined && IfNot)) ) if (Parser->HashIfEvaluateToLevel == Parser->HashIfLevel && ( (IsDefined && !IfNot) || (!IsDefined && IfNot)) )
{ {
/* #if is active, evaluate to this new level */ /* #if is active, evaluate to this new level */
@ -777,7 +777,7 @@ void LexHashIf(struct ParseState *Parser)
if (Token == TokenIdentifier) if (Token == TokenIdentifier)
{ {
/* look up a value from a macro definition */ /* look up a value from a macro definition */
if (!TableGet(&GlobalTable, IdentValue->Val->Identifier, &SavedValue)) if (!TableGet(&GlobalTable, IdentValue->Val->Identifier, &SavedValue, NULL, NULL))
ProgramFail(Parser, "'%s' is undefined", IdentValue->Val->Identifier); ProgramFail(Parser, "'%s' is undefined", IdentValue->Val->Identifier);
if (SavedValue->Typ->Base != TypeMacro) if (SavedValue->Typ->Base != TypeMacro)

View file

@ -128,7 +128,7 @@ struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueTyp
FuncValue->Val->FuncDef.Body.Pos = LexCopyTokens(&FuncBody, Parser); FuncValue->Val->FuncDef.Body.Pos = LexCopyTokens(&FuncBody, Parser);
/* is this function already in the global table? */ /* is this function already in the global table? */
if (TableGet(&GlobalTable, Identifier, &OldFuncValue)) if (TableGet(&GlobalTable, Identifier, &OldFuncValue, NULL, NULL))
{ {
if (OldFuncValue->Val->FuncDef.Body.Pos == NULL) if (OldFuncValue->Val->FuncDef.Body.Pos == NULL)
TableDelete(&GlobalTable, Identifier); /* override an old function prototype */ TableDelete(&GlobalTable, Identifier); /* override an old function prototype */
@ -137,7 +137,7 @@ struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueTyp
} }
} }
if (!TableSet(&GlobalTable, Identifier, FuncValue)) if (!TableSet(&GlobalTable, Identifier, FuncValue, Parser->Line, Parser->CharacterPos))
ProgramFail(Parser, "'%s' is already defined", Identifier); ProgramFail(Parser, "'%s' is already defined", Identifier);
return FuncValue; return FuncValue;
@ -227,7 +227,7 @@ int ParseDeclaration(struct ParseState *Parser, enum LexToken Token)
ProgramFail(Parser, "can't define a void variable"); ProgramFail(Parser, "can't define a void variable");
if (Parser->Mode == RunModeRun) if (Parser->Mode == RunModeRun)
NewVariable = VariableDefine(Parser, Identifier, NULL, Typ, TRUE); NewVariable = VariableDefineButIgnoreIdentical(Parser, Identifier, Typ);
if (LexGetToken(Parser, NULL, FALSE) == TokenAssign) if (LexGetToken(Parser, NULL, FALSE) == TokenAssign)
{ {
@ -304,7 +304,7 @@ void ParseMacroDefinition(struct ParseState *Parser)
LexToEndOfLine(Parser); LexToEndOfLine(Parser);
MacroValue->Val->MacroDef.Body.Pos = LexCopyTokens(&MacroValue->Val->MacroDef.Body, Parser); MacroValue->Val->MacroDef.Body.Pos = LexCopyTokens(&MacroValue->Val->MacroDef.Body, Parser);
if (!TableSet(&GlobalTable, MacroNameStr, MacroValue)) if (!TableSet(&GlobalTable, MacroNameStr, MacroValue, Parser->Line, Parser->CharacterPos))
ProgramFail(Parser, "'%s' is already defined", MacroNameStr); ProgramFail(Parser, "'%s' is already defined", MacroNameStr);
} }

View file

@ -208,6 +208,9 @@ struct Value
struct TableEntry struct TableEntry
{ {
struct TableEntry *Next; /* next item in this hash chain */ struct TableEntry *Next; /* next item in this hash chain */
unsigned short DeclLine; /* where the variable was declared */
unsigned short DeclColumn;
union TableEntryPayload union TableEntryPayload
{ {
struct ValueEntry struct ValueEntry
@ -321,8 +324,8 @@ void TableInit();
char *TableStrRegister(const char *Str); char *TableStrRegister(const char *Str);
char *TableStrRegister2(const char *Str, int Len); char *TableStrRegister2(const char *Str, int Len);
void TableInitTable(struct Table *Tbl, struct TableEntry **HashTable, int Size, int OnHeap); void TableInitTable(struct Table *Tbl, struct TableEntry **HashTable, int Size, int OnHeap);
int TableSet(struct Table *Tbl, char *Key, struct Value *Val); int TableSet(struct Table *Tbl, char *Key, struct Value *Val, int DeclLine, int DeclColumn);
int TableGet(struct Table *Tbl, const char *Key, struct Value **Val); int TableGet(struct Table *Tbl, const char *Key, struct Value **Val, int *DeclLine, int *DeclColumn);
struct Value *TableDelete(struct Table *Tbl, const char *Key); struct Value *TableDelete(struct Table *Tbl, const char *Key);
char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen); char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen);
void TableStrFree(); void TableStrFree();
@ -394,6 +397,7 @@ struct Value *VariableAllocValueFromType(struct ParseState *Parser, struct Value
struct Value *VariableAllocValueFromExistingData(struct ParseState *Parser, struct ValueType *Typ, union AnyValue *FromValue, int IsLValue, struct Value *LValueFrom); struct Value *VariableAllocValueFromExistingData(struct ParseState *Parser, struct ValueType *Typ, union AnyValue *FromValue, int IsLValue, struct Value *LValueFrom);
struct Value *VariableAllocValueShared(struct ParseState *Parser, struct Value *FromValue); struct Value *VariableAllocValueShared(struct ParseState *Parser, struct Value *FromValue);
struct Value *VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue, struct ValueType *Typ, int MakeWritable); struct Value *VariableDefine(struct ParseState *Parser, char *Ident, struct Value *InitValue, struct ValueType *Typ, int MakeWritable);
struct Value *VariableDefineButIgnoreIdentical(struct ParseState *Parser, char *Ident, struct ValueType *Typ);
int VariableDefined(const char *Ident); int VariableDefined(const char *Ident);
void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal); void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal);
void VariableDefinePlatformVar(struct ParseState *Parser, char *Ident, struct ValueType *Typ, union AnyValue *FromValue, int IsWritable); void VariableDefinePlatformVar(struct ParseState *Parser, char *Ident, struct ValueType *Typ, union AnyValue *FromValue, int IsWritable);

15
table.c
View file

@ -56,7 +56,7 @@ static struct TableEntry *TableSearch(struct Table *Tbl, const char *Key, int *A
/* set an identifier to a value. returns FALSE if it already exists. /* set an identifier to a value. returns FALSE if it already exists.
* Key must be a shared string from TableStrRegister() */ * Key must be a shared string from TableStrRegister() */
int TableSet(struct Table *Tbl, char *Key, struct Value *Val) int TableSet(struct Table *Tbl, char *Key, struct Value *Val, int DeclLine, int DeclColumn)
{ {
int AddAt; int AddAt;
struct TableEntry *FoundEntry = TableSearch(Tbl, Key, &AddAt); struct TableEntry *FoundEntry = TableSearch(Tbl, Key, &AddAt);
@ -64,6 +64,8 @@ int TableSet(struct Table *Tbl, char *Key, struct Value *Val)
if (FoundEntry == NULL) if (FoundEntry == NULL)
{ /* add it to the table */ { /* add it to the table */
struct TableEntry *NewEntry = VariableAlloc(NULL, sizeof(struct TableEntry), Tbl->OnHeap); struct TableEntry *NewEntry = VariableAlloc(NULL, sizeof(struct TableEntry), Tbl->OnHeap);
NewEntry->DeclLine = DeclLine;
NewEntry->DeclColumn = DeclColumn;
NewEntry->p.v.Key = Key; NewEntry->p.v.Key = Key;
NewEntry->p.v.Val = Val; NewEntry->p.v.Val = Val;
NewEntry->Next = Tbl->HashTable[AddAt]; NewEntry->Next = Tbl->HashTable[AddAt];
@ -76,7 +78,7 @@ int TableSet(struct Table *Tbl, char *Key, struct Value *Val)
/* find a value in a table. returns FALSE if not found. /* find a value in a table. returns FALSE if not found.
* Key must be a shared string from TableStrRegister() */ * Key must be a shared string from TableStrRegister() */
int TableGet(struct Table *Tbl, const char *Key, struct Value **Val) int TableGet(struct Table *Tbl, const char *Key, struct Value **Val, int *DeclLine, int *DeclColumn)
{ {
int AddAt; int AddAt;
struct TableEntry *FoundEntry = TableSearch(Tbl, Key, &AddAt); struct TableEntry *FoundEntry = TableSearch(Tbl, Key, &AddAt);
@ -84,6 +86,13 @@ int TableGet(struct Table *Tbl, const char *Key, struct Value **Val)
return FALSE; return FALSE;
*Val = FoundEntry->p.v.Val; *Val = FoundEntry->p.v.Val;
if (DeclLine != NULL)
{
*DeclLine = FoundEntry->DeclLine;
*DeclColumn = FoundEntry->DeclColumn;
}
return TRUE; return TRUE;
} }
@ -132,7 +141,7 @@ char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen)
return &FoundEntry->p.Key[0]; return &FoundEntry->p.Key[0];
else else
{ /* add it to the table - we economise by not allocating the whole structure here */ { /* add it to the table - we economise by not allocating the whole structure here */
struct TableEntry *NewEntry = HeapAllocMem(sizeof(struct TableEntry *) + IdentLen + 1); struct TableEntry *NewEntry = HeapAllocMem(sizeof(struct TableEntry) - sizeof(union TableEntryPayload) + IdentLen + 1);
if (NewEntry == NULL) if (NewEntry == NULL)
ProgramFail(NULL, "out of memory"); ProgramFail(NULL, "out of memory");

View file

@ -0,0 +1,10 @@
#include <stdio.h>
int a;
for (a = 0; a < 2; a++)
{
int b = a;
}
printf("it's all good\n");

View file

@ -0,0 +1 @@
it's all good

View file

@ -38,7 +38,8 @@ TESTS= 00_assignment.test \
39_typedef.test \ 39_typedef.test \
40_stdio.test \ 40_stdio.test \
41_hashif.test \ 41_hashif.test \
43_void_param.test 43_void_param.test \
44_scoped_declarations.test
%.test: %.expect %.c %.test: %.expect %.c
@echo Test: $*... @echo Test: $*...

2
type.c
View file

@ -233,7 +233,7 @@ void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ, int IsSt
(*Typ)->Sizeof = TypeSizeValue(MemberValue); (*Typ)->Sizeof = TypeSizeValue(MemberValue);
} }
if (!TableSet((*Typ)->Members, MemberIdentifier, MemberValue)) if (!TableSet((*Typ)->Members, MemberIdentifier, MemberValue, Parser->Line, Parser->CharacterPos))
ProgramFail(Parser, "member '%s' already defined", &MemberIdentifier); ProgramFail(Parser, "member '%s' already defined", &MemberIdentifier);
if (LexGetToken(Parser, NULL, TRUE) != TokenSemicolon) if (LexGetToken(Parser, NULL, TRUE) != TokenSemicolon)

View file

@ -161,20 +161,34 @@ struct Value *VariableDefine(struct ParseState *Parser, char *Ident, struct Valu
AssignValue->IsLValue = MakeWritable; AssignValue->IsLValue = MakeWritable;
if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, Ident, AssignValue)) if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, Ident, AssignValue, Parser ? Parser->Line : 0, Parser ? Parser->CharacterPos : 0))
ProgramFail(Parser, "'%s' is already defined", Ident); ProgramFail(Parser, "'%s' is already defined", Ident);
return AssignValue; return AssignValue;
} }
/* define a variable. Ident must be registered. If it's a redefinition from the same declaration don't throw an error */
struct Value *VariableDefineButIgnoreIdentical(struct ParseState *Parser, char *Ident, struct ValueType *Typ)
{
struct Value *ExistingValue;
int DeclLine;
int DeclColumn;
if (Parser->Line != 0 && TableGet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, Ident, &ExistingValue, &DeclLine, &DeclColumn)
&& DeclLine == Parser->Line && DeclColumn == Parser->CharacterPos)
return ExistingValue;
else
return VariableDefine(Parser, Ident, NULL, Typ, TRUE);
}
/* check if a variable with a given name is defined. Ident must be registered */ /* check if a variable with a given name is defined. Ident must be registered */
int VariableDefined(const char *Ident) int VariableDefined(const char *Ident)
{ {
struct Value *FoundValue; struct Value *FoundValue;
if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, &FoundValue)) if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, &FoundValue, NULL, NULL))
{ {
if (!TableGet(&GlobalTable, Ident, &FoundValue)) if (!TableGet(&GlobalTable, Ident, &FoundValue, NULL, NULL))
return FALSE; return FALSE;
} }
@ -184,9 +198,9 @@ int VariableDefined(const char *Ident)
/* get the value of a variable. must be defined. Ident must be registered */ /* get the value of a variable. must be defined. Ident must be registered */
void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal) void VariableGet(struct ParseState *Parser, const char *Ident, struct Value **LVal)
{ {
if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, LVal)) if (TopStackFrame == NULL || !TableGet(&TopStackFrame->LocalTable, Ident, LVal, NULL, NULL))
{ {
if (!TableGet(&GlobalTable, Ident, LVal)) if (!TableGet(&GlobalTable, Ident, LVal, NULL, NULL))
ProgramFail(Parser, "'%s' is undefined", Ident); ProgramFail(Parser, "'%s' is undefined", Ident);
} }
} }
@ -198,7 +212,7 @@ void VariableDefinePlatformVar(struct ParseState *Parser, char *Ident, struct Va
SomeValue->Typ = Typ; SomeValue->Typ = Typ;
SomeValue->Val = FromValue; SomeValue->Val = FromValue;
if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, TableStrRegister(Ident), SomeValue)) if (!TableSet((TopStackFrame == NULL) ? &GlobalTable : &TopStackFrame->LocalTable, TableStrRegister(Ident), SomeValue, Parser ? Parser->Line : 0, Parser ? Parser->CharacterPos : 0))
ProgramFail(Parser, "'%s' is already defined", Ident); ProgramFail(Parser, "'%s' is already defined", Ident);
} }
@ -261,7 +275,7 @@ struct Value *VariableStringLiteralGet(char *Ident)
{ {
struct Value *LVal = NULL; struct Value *LVal = NULL;
if (TableGet(&StringLiteralTable, Ident, &LVal)) if (TableGet(&StringLiteralTable, Ident, &LVal, NULL, NULL))
return LVal; return LVal;
else else
return NULL; return NULL;
@ -270,7 +284,7 @@ struct Value *VariableStringLiteralGet(char *Ident)
/* define a string literal. assumes that Ident is already registered */ /* define a string literal. assumes that Ident is already registered */
void VariableStringLiteralDefine(char *Ident, struct Value *Val) void VariableStringLiteralDefine(char *Ident, struct Value *Val)
{ {
TableSet(&StringLiteralTable, Ident, Val); TableSet(&StringLiteralTable, Ident, Val, 0, 0);
} }
/* check a pointer for validity and dereference it for use */ /* check a pointer for validity and dereference it for use */