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:
parent
d87d25fede
commit
036f3efa8b
|
@ -767,7 +767,7 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack *
|
|||
else if (Op == TokenAssign && TopInt == 0)
|
||||
{
|
||||
/* 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);
|
||||
ExpressionStackPushValueNode(Parser, StackTop, BottomValue);
|
||||
}
|
||||
|
@ -785,7 +785,7 @@ void ExpressionInfixOperator(struct ParseState *Parser, struct ExpressionStack *
|
|||
else
|
||||
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;
|
||||
ExpressionStackPushValueNode(Parser, StackTop, BottomValue);
|
||||
}
|
||||
|
@ -963,7 +963,7 @@ void ExpressionGetStructElement(struct ParseState *Parser, struct ExpressionStac
|
|||
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);
|
||||
|
||||
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);
|
||||
|
||||
/* pop the value - assume it'll still be there until we're done */
|
||||
|
|
4
lex.c
4
lex.c
|
@ -755,7 +755,7 @@ void LexHashIfdef(struct ParseState *Parser, int IfNot)
|
|||
ProgramFail(Parser, "identifier expected");
|
||||
|
||||
/* 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 is active, evaluate to this new level */
|
||||
|
@ -777,7 +777,7 @@ void LexHashIf(struct ParseState *Parser)
|
|||
if (Token == TokenIdentifier)
|
||||
{
|
||||
/* 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);
|
||||
|
||||
if (SavedValue->Typ->Base != TypeMacro)
|
||||
|
|
8
parse.c
8
parse.c
|
@ -128,7 +128,7 @@ struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueTyp
|
|||
FuncValue->Val->FuncDef.Body.Pos = LexCopyTokens(&FuncBody, Parser);
|
||||
|
||||
/* 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)
|
||||
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);
|
||||
|
||||
return FuncValue;
|
||||
|
@ -227,7 +227,7 @@ int ParseDeclaration(struct ParseState *Parser, enum LexToken Token)
|
|||
ProgramFail(Parser, "can't define a void variable");
|
||||
|
||||
if (Parser->Mode == RunModeRun)
|
||||
NewVariable = VariableDefine(Parser, Identifier, NULL, Typ, TRUE);
|
||||
NewVariable = VariableDefineButIgnoreIdentical(Parser, Identifier, Typ);
|
||||
|
||||
if (LexGetToken(Parser, NULL, FALSE) == TokenAssign)
|
||||
{
|
||||
|
@ -304,7 +304,7 @@ void ParseMacroDefinition(struct ParseState *Parser)
|
|||
LexToEndOfLine(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);
|
||||
}
|
||||
|
||||
|
|
8
picoc.h
8
picoc.h
|
@ -208,6 +208,9 @@ struct Value
|
|||
struct TableEntry
|
||||
{
|
||||
struct TableEntry *Next; /* next item in this hash chain */
|
||||
unsigned short DeclLine; /* where the variable was declared */
|
||||
unsigned short DeclColumn;
|
||||
|
||||
union TableEntryPayload
|
||||
{
|
||||
struct ValueEntry
|
||||
|
@ -321,8 +324,8 @@ void TableInit();
|
|||
char *TableStrRegister(const char *Str);
|
||||
char *TableStrRegister2(const char *Str, int Len);
|
||||
void TableInitTable(struct Table *Tbl, struct TableEntry **HashTable, int Size, int OnHeap);
|
||||
int TableSet(struct Table *Tbl, char *Key, struct Value *Val);
|
||||
int TableGet(struct Table *Tbl, const 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 *DeclLine, int *DeclColumn);
|
||||
struct Value *TableDelete(struct Table *Tbl, const char *Key);
|
||||
char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen);
|
||||
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 *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 *VariableDefineButIgnoreIdentical(struct ParseState *Parser, char *Ident, struct ValueType *Typ);
|
||||
int VariableDefined(const char *Ident);
|
||||
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);
|
||||
|
|
15
table.c
15
table.c
|
@ -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.
|
||||
* 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;
|
||||
struct TableEntry *FoundEntry = TableSearch(Tbl, Key, &AddAt);
|
||||
|
@ -64,6 +64,8 @@ int TableSet(struct Table *Tbl, char *Key, struct Value *Val)
|
|||
if (FoundEntry == NULL)
|
||||
{ /* add it to the table */
|
||||
struct TableEntry *NewEntry = VariableAlloc(NULL, sizeof(struct TableEntry), Tbl->OnHeap);
|
||||
NewEntry->DeclLine = DeclLine;
|
||||
NewEntry->DeclColumn = DeclColumn;
|
||||
NewEntry->p.v.Key = Key;
|
||||
NewEntry->p.v.Val = Val;
|
||||
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.
|
||||
* 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;
|
||||
struct TableEntry *FoundEntry = TableSearch(Tbl, Key, &AddAt);
|
||||
|
@ -84,6 +86,13 @@ int TableGet(struct Table *Tbl, const char *Key, struct Value **Val)
|
|||
return FALSE;
|
||||
|
||||
*Val = FoundEntry->p.v.Val;
|
||||
|
||||
if (DeclLine != NULL)
|
||||
{
|
||||
*DeclLine = FoundEntry->DeclLine;
|
||||
*DeclColumn = FoundEntry->DeclColumn;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -132,7 +141,7 @@ char *TableSetIdentifier(struct Table *Tbl, const char *Ident, int IdentLen)
|
|||
return &FoundEntry->p.Key[0];
|
||||
else
|
||||
{ /* 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)
|
||||
ProgramFail(NULL, "out of memory");
|
||||
|
||||
|
|
10
tests/44_scoped_declarations.c
Normal file
10
tests/44_scoped_declarations.c
Normal 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");
|
1
tests/44_scoped_declarations.expect
Normal file
1
tests/44_scoped_declarations.expect
Normal file
|
@ -0,0 +1 @@
|
|||
it's all good
|
|
@ -38,7 +38,8 @@ TESTS= 00_assignment.test \
|
|||
39_typedef.test \
|
||||
40_stdio.test \
|
||||
41_hashif.test \
|
||||
43_void_param.test
|
||||
43_void_param.test \
|
||||
44_scoped_declarations.test
|
||||
|
||||
%.test: %.expect %.c
|
||||
@echo Test: $*...
|
||||
|
|
2
type.c
2
type.c
|
@ -233,7 +233,7 @@ void TypeParseStruct(struct ParseState *Parser, struct ValueType **Typ, int IsSt
|
|||
(*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);
|
||||
|
||||
if (LexGetToken(Parser, NULL, TRUE) != TokenSemicolon)
|
||||
|
|
30
variable.c
30
variable.c
|
@ -161,20 +161,34 @@ struct Value *VariableDefine(struct ParseState *Parser, char *Ident, struct Valu
|
|||
|
||||
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);
|
||||
|
||||
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 */
|
||||
int VariableDefined(const char *Ident)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -184,9 +198,9 @@ int VariableDefined(const char *Ident)
|
|||
/* get the value of a variable. must be defined. Ident must be registered */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -198,7 +212,7 @@ void VariableDefinePlatformVar(struct ParseState *Parser, char *Ident, struct Va
|
|||
SomeValue->Typ = Typ;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -261,7 +275,7 @@ struct Value *VariableStringLiteralGet(char *Ident)
|
|||
{
|
||||
struct Value *LVal = NULL;
|
||||
|
||||
if (TableGet(&StringLiteralTable, Ident, &LVal))
|
||||
if (TableGet(&StringLiteralTable, Ident, &LVal, NULL, NULL))
|
||||
return LVal;
|
||||
else
|
||||
return NULL;
|
||||
|
@ -270,7 +284,7 @@ struct Value *VariableStringLiteralGet(char *Ident)
|
|||
/* define a string literal. assumes that Ident is already registered */
|
||||
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 */
|
||||
|
|
Loading…
Reference in a new issue