diff --git a/clibrary.c b/clibrary.c index 8988fd5..d6ca7ca 100644 --- a/clibrary.c +++ b/clibrary.c @@ -63,6 +63,7 @@ void PrintType(struct ValueType *Typ, IOFILE *Stream) case TypeUnsignedInt: PrintStr("unsigned int", Stream); break; case TypeUnsignedShort: PrintStr("unsigned short", Stream); break; case TypeUnsignedLong: PrintStr("unsigned long", Stream); break; + case TypeUnsignedChar: PrintStr("unsigned char", Stream); break; #ifndef NO_FP case TypeFP: PrintStr("double", Stream); break; #endif diff --git a/cstdlib/stdio.c b/cstdlib/stdio.c index 0234e55..486fb78 100644 --- a/cstdlib/stdio.c +++ b/cstdlib/stdio.c @@ -7,7 +7,7 @@ #define MAX_FORMAT 80 #define MAX_SCANF_ARGS 10 -static int ZeroValue = 0; +static int Stdio_ZeroValue = 0; static int EOFValue = EOF; static int SEEK_SETValue = SEEK_SET; static int SEEK_CURValue = SEEK_CUR; @@ -103,7 +103,7 @@ void StdioOutPuts(const char *Str, StdOutStream *Stream) } /* printf-style format of an int or other word-sized object */ -void StdioFprintfWord(StdOutStream *Stream, const char *Format, unsigned int Value) +void StdioFprintfWord(StdOutStream *Stream, const char *Format, unsigned long Value) { if (Stream->FilePtr != NULL) Stream->CharCount += fprintf(Stream->FilePtr, Format, Value); @@ -712,7 +712,7 @@ void StdioSetupFunc(Picoc *pc) /* define NULL, TRUE and FALSE */ if (!VariableDefined(pc, TableStrRegister(pc, "NULL"))) - VariableDefinePlatformVar(pc, NULL, "NULL", &pc->IntType, (union AnyValue *)&ZeroValue, FALSE); + VariableDefinePlatformVar(pc, NULL, "NULL", &pc->IntType, (union AnyValue *)&Stdio_ZeroValue, FALSE); } /* portability-related I/O calls */ diff --git a/cstdlib/stdlib.c b/cstdlib/stdlib.c index 2a392e0..91e1a38 100644 --- a/cstdlib/stdlib.c +++ b/cstdlib/stdlib.c @@ -3,7 +3,7 @@ #ifndef BUILTIN_MINI_STDLIB -static int ZeroValue = 0; +static int Stdlib_ZeroValue = 0; #ifndef NO_FP void StdlibAtof(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) @@ -168,7 +168,7 @@ void StdlibSetupFunc(Picoc *pc) { /* define NULL, TRUE and FALSE */ if (!VariableDefined(pc, TableStrRegister(pc, "NULL"))) - VariableDefinePlatformVar(pc, NULL, "NULL", &pc->IntType, (union AnyValue *)&ZeroValue, FALSE); + VariableDefinePlatformVar(pc, NULL, "NULL", &pc->IntType, (union AnyValue *)&Stdlib_ZeroValue, FALSE); } #endif /* !BUILTIN_MINI_STDLIB */ diff --git a/cstdlib/string.c b/cstdlib/string.c index a42ce90..982a1b7 100644 --- a/cstdlib/string.c +++ b/cstdlib/string.c @@ -3,7 +3,7 @@ #ifndef BUILTIN_MINI_STDLIB -static int ZeroValue = 0; +static int String_ZeroValue = 0; void StringStrcpy(struct ParseState *Parser, struct Value *ReturnValue, struct Value **Param, int NumArgs) { @@ -180,7 +180,7 @@ void StringSetupFunc(Picoc *pc) { /* define NULL */ if (!VariableDefined(pc, TableStrRegister(pc, "NULL"))) - VariableDefinePlatformVar(pc, NULL, "NULL", &pc->IntType, (union AnyValue *)&ZeroValue, FALSE); + VariableDefinePlatformVar(pc, NULL, "NULL", &pc->IntType, (union AnyValue *)&String_ZeroValue, FALSE); } #endif /* !BUILTIN_MINI_STDLIB */ diff --git a/expression.c b/expression.c index d5b7835..393425f 100644 --- a/expression.c +++ b/expression.c @@ -6,7 +6,6 @@ /* whether evaluation is left to right for a given precedence level */ #define IS_LEFT_TO_RIGHT(p) ((p) != 2 && (p) != 14) #define BRACKET_PRECEDENCE 20 -#define IS_TYPE_TOKEN(t) ((t) >= TokenIntType && (t) <= TokenUnsignedType) /* If the destination is not float, we can't assign a floating value to it, we need to convert it to integer instead */ #define ASSIGN_FP_OR_INT(value) \ @@ -142,6 +141,26 @@ void ExpressionStackShow(struct ExpressionStack *StackTop) } #endif +int IsTypeToken(struct ParseState * Parser, enum LexToken t, struct Value * LexValue) +{ + if (t >= TokenIntType && t <= TokenUnsignedType) + return 1; /* base type */ + + /* typedef'ed type? */ + if (t == TokenIdentifier) /* see TypeParseFront, case TokenIdentifier and ParseTypedef */ + { + struct Value * VarValue; + if (VariableDefined(Parser->pc, LexValue->Val->Pointer)) + { + VariableGet(Parser->pc, Parser, LexValue->Val->Pointer, &VarValue); + if (VarValue->Typ == &Parser->pc->TypeType) + return 1; + } + } + + return 0; +} + long ExpressionCoerceInteger(struct Value *Val) { switch (Val->Typ->Base) @@ -153,6 +172,7 @@ long ExpressionCoerceInteger(struct Value *Val) case TypeUnsignedInt: return (long)Val->Val->UnsignedInteger; case TypeUnsignedShort: return (long)Val->Val->UnsignedShortInteger; case TypeUnsignedLong: return (long)Val->Val->UnsignedLongInteger; + case TypeUnsignedChar: return (long)Val->Val->UnsignedCharacter; case TypePointer: return (long)Val->Val->Pointer; #ifndef NO_FP case TypeFP: return (long)Val->Val->FP; @@ -172,6 +192,7 @@ unsigned long ExpressionCoerceUnsignedInteger(struct Value *Val) case TypeUnsignedInt: return (unsigned long)Val->Val->UnsignedInteger; case TypeUnsignedShort: return (unsigned long)Val->Val->UnsignedShortInteger; case TypeUnsignedLong: return (unsigned long)Val->Val->UnsignedLongInteger; + case TypeUnsignedChar: return (unsigned long)Val->Val->UnsignedCharacter; case TypePointer: return (unsigned long)Val->Val->Pointer; #ifndef NO_FP case TypeFP: return (unsigned long)Val->Val->FP; @@ -196,6 +217,7 @@ double ExpressionCoerceFP(struct Value *Val) case TypeUnsignedInt: UnsignedVal = Val->Val->UnsignedInteger; return (double)UnsignedVal; case TypeUnsignedShort: UnsignedVal = Val->Val->UnsignedShortInteger; return (double)UnsignedVal; case TypeUnsignedLong: UnsignedVal = Val->Val->UnsignedLongInteger; return (double)UnsignedVal; + case TypeUnsignedChar: UnsignedVal = Val->Val->UnsignedCharacter; return (double)UnsignedVal; case TypeFP: return Val->Val->FP; default: return 0.0; } @@ -209,6 +231,7 @@ double ExpressionCoerceFP(struct Value *Val) case TypeUnsignedInt: return (double)Val->Val->UnsignedInteger; case TypeUnsignedShort: return (double)Val->Val->UnsignedShortInteger; case TypeUnsignedLong: return (double)Val->Val->UnsignedLongInteger; + case TypeUnsignedChar: return (double)Val->Val->UnsignedCharacter; case TypeFP: return (double)Val->Val->FP; default: return 0.0; } @@ -233,11 +256,12 @@ long ExpressionAssignInt(struct ParseState *Parser, struct Value *DestValue, lon { case TypeInt: DestValue->Val->Integer = FromInt; break; case TypeShort: DestValue->Val->ShortInteger = (short)FromInt; break; - case TypeChar: DestValue->Val->Character = (unsigned char)FromInt; break; + case TypeChar: DestValue->Val->Character = (char)FromInt; break; case TypeLong: DestValue->Val->LongInteger = (long)FromInt; break; case TypeUnsignedInt: DestValue->Val->UnsignedInteger = (unsigned int)FromInt; break; case TypeUnsignedShort: DestValue->Val->UnsignedShortInteger = (unsigned short)FromInt; break; case TypeUnsignedLong: DestValue->Val->UnsignedLongInteger = (unsigned long)FromInt; break; + case TypeUnsignedChar: DestValue->Val->UnsignedCharacter = (unsigned char)FromInt; break; default: break; } return Result; @@ -376,11 +400,12 @@ void ExpressionAssign(struct ParseState *Parser, struct Value *DestValue, struct { case TypeInt: DestValue->Val->Integer = ExpressionCoerceInteger(SourceValue); break; case TypeShort: DestValue->Val->ShortInteger = (short)ExpressionCoerceInteger(SourceValue); break; - case TypeChar: DestValue->Val->Character = (unsigned char)ExpressionCoerceUnsignedInteger(SourceValue); break; + case TypeChar: DestValue->Val->Character = (char)ExpressionCoerceInteger(SourceValue); break; case TypeLong: DestValue->Val->LongInteger = ExpressionCoerceInteger(SourceValue); break; case TypeUnsignedInt: DestValue->Val->UnsignedInteger = ExpressionCoerceUnsignedInteger(SourceValue); break; case TypeUnsignedShort: DestValue->Val->UnsignedShortInteger = (unsigned short)ExpressionCoerceUnsignedInteger(SourceValue); break; case TypeUnsignedLong: DestValue->Val->UnsignedLongInteger = ExpressionCoerceUnsignedInteger(SourceValue); break; + case TypeUnsignedChar: DestValue->Val->UnsignedCharacter = (unsigned char)ExpressionCoerceUnsignedInteger(SourceValue); break; #ifndef NO_FP case TypeFP: @@ -409,6 +434,29 @@ void ExpressionAssign(struct ParseState *Parser, struct Value *DestValue, struct } } + /* char array = "abcd" */ + if (DestValue->Typ->FromType->Base == TypeChar && SourceValue->Typ->Base == TypePointer && SourceValue->Typ->FromType->Base == TypeChar) + { + if (DestValue->Typ->ArraySize == 0) /* char x[] = "abcd", x is unsized */ + { + int Size = strlen(SourceValue->Val->Pointer) + 1; + #ifdef DEBUG_ARRAY_INITIALIZER + PRINT_SOURCE_POS; + fprintf(stderr, "str size: %d\n", Size); + #endif + DestValue->Typ = TypeGetMatching(Parser->pc, Parser, DestValue->Typ->FromType, DestValue->Typ->Base, Size, DestValue->Typ->Identifier, TRUE); + VariableRealloc(Parser, DestValue, TypeSizeValue(DestValue, FALSE)); + } + /* else, it's char x[10] = "abcd" */ + + #ifdef DEBUG_ARRAY_INITIALIZER + PRINT_SOURCE_POS; + fprintf(stderr, "char[%d] from char* (len=%d)\n", DestValue->Typ->ArraySize, strlen(SourceValue->Val->Pointer)); + #endif + memcpy((void *)DestValue->Val, SourceValue->Val->Pointer, TypeSizeValue(DestValue, FALSE)); + break; + } + if (DestValue->Typ != SourceValue->Typ) AssignFail(Parser, "%t from %t", DestValue->Typ, SourceValue->Typ, 0, 0, FuncName, ParamNo); @@ -508,6 +556,9 @@ void ExpressionPrefixOperator(struct ParseState *Parser, struct ExpressionStack { case TokenPlus: ResultFP = TopValue->Val->FP; break; case TokenMinus: ResultFP = -TopValue->Val->FP; break; + case TokenIncrement: ResultFP = ExpressionAssignFP(Parser, TopValue, TopValue->Val->FP+1); break; + case TokenDecrement: ResultFP = ExpressionAssignFP(Parser, TopValue, TopValue->Val->FP-1); break; + case TokenUnaryNot: ResultFP = !TopValue->Val->FP; break; default: ProgramFail(Parser, "invalid operation"); break; } @@ -567,6 +618,23 @@ void ExpressionPrefixOperator(struct ParseState *Parser, struct ExpressionStack void ExpressionPostfixOperator(struct ParseState *Parser, struct ExpressionStack **StackTop, enum LexToken Op, struct Value *TopValue) { debugf("ExpressionPostfixOperator()\n"); +#ifndef NO_FP + if (TopValue->Typ == &Parser->pc->FPType) + { + /* floating point prefix arithmetic */ + double ResultFP = 0.0; + + switch (Op) + { + case TokenIncrement: ResultFP = ExpressionAssignFP(Parser, TopValue, TopValue->Val->FP+1); break; + case TokenDecrement: ResultFP = ExpressionAssignFP(Parser, TopValue, TopValue->Val->FP-1); break; + default: ProgramFail(Parser, "invalid operation"); break; + } + + ExpressionPushFP(Parser, StackTop, ResultFP); + } + else +#endif if (IS_NUMERIC_COERCIBLE(TopValue)) { long ResultInt = 0; @@ -861,7 +929,7 @@ void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack * *StackTop = TopOperatorNode->Next; /* do the prefix operation */ - if (Parser->Mode == RunModeRun && FoundPrecedence < *IgnorePrecedence) + if (Parser->Mode == RunModeRun /* && FoundPrecedence < *IgnorePrecedence */) { /* run the operator */ ExpressionPrefixOperator(Parser, StackTop, TopOperatorNode->Op, TopValue); @@ -884,7 +952,7 @@ void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack * *StackTop = TopStackNode->Next->Next; /* do the postfix operation */ - if (Parser->Mode == RunModeRun && FoundPrecedence < *IgnorePrecedence) + if (Parser->Mode == RunModeRun /* && FoundPrecedence < *IgnorePrecedence */) { /* run the operator */ ExpressionPostfixOperator(Parser, StackTop, TopOperatorNode->Op, TopValue); @@ -911,7 +979,7 @@ void ExpressionStackCollapse(struct ParseState *Parser, struct ExpressionStack * *StackTop = TopOperatorNode->Next->Next; /* do the infix operation */ - if (Parser->Mode == RunModeRun && FoundPrecedence <= *IgnorePrecedence) + if (Parser->Mode == RunModeRun /* && FoundPrecedence <= *IgnorePrecedence */) { /* run the operator */ ExpressionInfixOperator(Parser, StackTop, TopOperatorNode->Op, BottomValue, TopValue); @@ -982,7 +1050,7 @@ void ExpressionGetStructElement(struct ParseState *Parser, struct ExpressionStac struct Value *StructVal = ParamVal; struct ValueType *StructType = ParamVal->Typ; char *DerefDataLoc = (char *)ParamVal->Val; - struct Value *MemberValue; + struct Value *MemberValue = NULL; struct Value *Result; /* if we're doing '->' dereference the struct pointer first */ @@ -1044,7 +1112,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result) { /* it's either a new bracket level or a cast */ enum LexToken BracketToken = LexGetToken(Parser, &LexValue, FALSE); - if (IS_TYPE_TOKEN(BracketToken) && (StackTop == NULL || StackTop->Op != TokenSizeof) ) + if (IsTypeToken(Parser, BracketToken, LexValue) && (StackTop == NULL || StackTop->Op != TokenSizeof) ) { /* it's a cast - get the new type */ struct ValueType *CastType; @@ -1073,8 +1141,22 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result) else { /* scan and collapse the stack to the precedence of this operator, then push */ + + /* take some extra care for double prefix operators, e.g. x = - -5, or x = **y */ + int NextToken = LexGetToken(Parser, NULL, FALSE); + int TempPrecedenceBoost = 0; + if (NextToken > TokenComma && NextToken < TokenOpenBracket) + { + int NextPrecedence = OperatorPrecedence[(int)NextToken].PrefixPrecedence; + + /* two prefix operators with equal precedence? make sure the innermost one runs first */ + /* XXX - probably not correct, but can't find a test that fails at this */ + if (LocalPrecedence == NextPrecedence) + TempPrecedenceBoost = -1; + } + ExpressionStackCollapse(Parser, &StackTop, Precedence, &IgnorePrecedence); - ExpressionStackPushOperator(Parser, &StackTop, OrderPrefix, Token, Precedence); + ExpressionStackPushOperator(Parser, &StackTop, OrderPrefix, Token, Precedence + TempPrecedenceBoost); } } else @@ -1170,7 +1252,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result) } else { - if (Parser->Mode == RunModeRun && Precedence < IgnorePrecedence) + if (Parser->Mode == RunModeRun /* && Precedence < IgnorePrecedence */) { struct Value *VariableValue = NULL; @@ -1215,7 +1297,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result) PrefixState = FALSE; ExpressionStackPushValue(Parser, &StackTop, LexValue); } - else if (IS_TYPE_TOKEN(Token)) + else if (IsTypeToken(Parser, Token, LexValue)) { /* it's a type. push it on the stack like a value. this is used in sizeof() */ struct ValueType *Typ; @@ -1357,7 +1439,7 @@ void ExpressionParseMacroCall(struct ParseState *Parser, struct ExpressionStack void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionStack **StackTop, const char *FuncName, int RunIt) { struct Value *ReturnValue = NULL; - struct Value *FuncValue; + struct Value *FuncValue = NULL; struct Value *Param; struct Value **ParamArray = NULL; int ArgCount; @@ -1440,6 +1522,7 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta /* run a user-defined function */ struct ParseState FuncParser; int Count; + int OldScopeID = Parser->ScopeID; if (FuncValue->Val->FuncDef.Body.Pos == NULL) ProgramFail(Parser, "'%s' is undefined", FuncName); @@ -1448,12 +1531,18 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta VariableStackFrameAdd(Parser, FuncName, FuncValue->Val->FuncDef.Intrinsic ? FuncValue->Val->FuncDef.NumParams : 0); Parser->pc->TopStackFrame->NumParams = ArgCount; Parser->pc->TopStackFrame->ReturnValue = ReturnValue; + + /* Function parameters should not go out of scope */ + Parser->ScopeID = -1; + for (Count = 0; Count < FuncValue->Val->FuncDef.NumParams; Count++) VariableDefine(Parser->pc, Parser, FuncValue->Val->FuncDef.ParamName[Count], ParamArray[Count], NULL, TRUE); + + Parser->ScopeID = OldScopeID; if (ParseStatement(&FuncParser, TRUE) != ParseResultOk) ProgramFail(&FuncParser, "function body expected"); - + if (RunIt) { if (FuncParser.Mode == RunModeRun && FuncValue->Val->FuncDef.ReturnType != &Parser->pc->VoidType) diff --git a/interpreter.h b/interpreter.h index bca3458..616fffa 100644 --- a/interpreter.h +++ b/interpreter.h @@ -26,6 +26,10 @@ #define GETS_BUF_MAX 256 +/* for debugging */ +#define PRINT_SOURCE_POS ({ PrintSourceTextErrorLine(Parser->pc->CStdOut, Parser->FileName, Parser->SourceText, Parser->Line, Parser->CharacterPos); PlatformPrintf(Parser->pc->CStdOut, "\n"); }) +#define PRINT_TYPE(typ) PlatformPrintf(Parser->pc->CStdOut, "%t\n", typ); + /* small processors use a simplified FILE * for stdio, otherwise use the system FILE * */ #ifdef BUILTIN_MINI_STDLIB typedef struct OutputStream IOFILE; @@ -123,6 +127,7 @@ struct ParseState short int HashIfLevel; /* how many "if"s we're nested down */ short int HashIfEvaluateToLevel; /* if we're not evaluating an if branch, what the last evaluated level was */ char DebugMode; /* debugging mode */ + int ScopeID; /* for keeping track of local variables (free them after they go out of scope) */ }; /* values */ @@ -131,10 +136,11 @@ enum BaseType TypeVoid, /* no type */ TypeInt, /* integer */ TypeShort, /* short integer */ - TypeChar, /* a single character (unsigned) */ + TypeChar, /* a single character (signed) */ TypeLong, /* long integer */ TypeUnsignedInt, /* unsigned integer */ TypeUnsignedShort, /* unsigned short integer */ + TypeUnsignedChar, /* unsigned 8-bit number */ /* must be before unsigned long */ TypeUnsignedLong, /* unsigned long integer */ #ifndef NO_FP TypeFP, /* floating point */ @@ -189,13 +195,14 @@ struct MacroDef /* values */ union AnyValue { - unsigned char Character; + char Character; short ShortInteger; int Integer; long LongInteger; unsigned short UnsignedShortInteger; unsigned int UnsignedInteger; unsigned long UnsignedLongInteger; + unsigned char UnsignedCharacter; char *Identifier; char ArrayMem[2]; /* placeholder for where the data starts, doesn't point to it */ struct ValueType *Typ; @@ -216,6 +223,8 @@ struct Value char ValOnStack; /* the AnyValue is on the stack along with this Value */ char AnyValOnHeap; /* the AnyValue is separately allocated from the Value on the heap */ char IsLValue; /* is modifiable and is allocated somewhere we can usefully modify it */ + int ScopeID; /* to know when it goes out of scope */ + char OutOfScope; }; /* hash table data structure */ @@ -414,6 +423,7 @@ struct Picoc_Struct struct ValueType UnsignedIntType; struct ValueType UnsignedShortType; struct ValueType UnsignedLongType; + struct ValueType UnsignedCharType; #ifndef NO_FP struct ValueType FPType; #endif @@ -543,6 +553,7 @@ struct Value *VariableAllocValueShared(struct ParseState *Parser, struct Value * struct Value *VariableDefine(Picoc *pc, 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 IsStatic, int *FirstVisit); int VariableDefined(Picoc *pc, const char *Ident); +int VariableDefinedAndOutOfScope(Picoc *pc, const char *Ident); void VariableRealloc(struct ParseState *Parser, struct Value *FromValue, int NewSize); void VariableGet(Picoc *pc, struct ParseState *Parser, const char *Ident, struct Value **LVal); void VariableDefinePlatformVar(Picoc *pc, struct ParseState *Parser, char *Ident, struct ValueType *Typ, union AnyValue *FromValue, int IsWritable); @@ -551,6 +562,8 @@ void VariableStackFramePop(struct ParseState *Parser); struct Value *VariableStringLiteralGet(Picoc *pc, char *Ident); void VariableStringLiteralDefine(Picoc *pc, char *Ident, struct Value *Val); void *VariableDereferencePointer(struct ParseState *Parser, struct Value *PointerValue, struct Value **DerefVal, int *DerefOffset, struct ValueType **DerefType, int *DerefIsLValue); +int VariableScopeBegin(struct ParseState * Parser, int* PrevScopeID); +void VariableScopeEnd(struct ParseState * Parser, int ScopeID, int PrevScopeID); /* clibrary.c */ void BasicIOInit(Picoc *pc); diff --git a/lex.c b/lex.c index 042f933..9524b5b 100644 --- a/lex.c +++ b/lex.c @@ -129,13 +129,18 @@ enum LexToken LexCheckReservedWord(Picoc *pc, const char *Word) /* get a numeric literal - used while scanning */ enum LexToken LexGetNumber(Picoc *pc, struct LexState *Lexer, struct Value *Value) { - int Result = 0; - int Base = 10; + long Result = 0; + long Base = 10; enum LexToken ResultToken; #ifndef NO_FP double FPResult; double FPDiv; #endif + /* long/unsigned flags */ +#if 0 /* unused for now */ + char IsLong = 0; + char IsUnsigned = 0; +#endif if (*Lexer->Pos == '0') { @@ -155,46 +160,57 @@ enum LexToken LexGetNumber(Picoc *pc, struct LexState *Lexer, struct Value *Valu /* get the value */ for (; Lexer->Pos != Lexer->End && IS_BASE_DIGIT(*Lexer->Pos, Base); LEXER_INC(Lexer)) Result = Result * Base + GET_BASE_DIGIT(*Lexer->Pos); + + if (*Lexer->Pos == 'u' || *Lexer->Pos == 'U') + { + LEXER_INC(Lexer); + /* IsUnsigned = 1; */ + } + if (*Lexer->Pos == 'l' || *Lexer->Pos == 'L') + { + LEXER_INC(Lexer); + /* IsLong = 1; */ + } - if (Result >= 0 && Result <= MAX_CHAR_VALUE) - { - Value->Typ = &pc->CharType; - Value->Val->Character = Result; - ResultToken = TokenCharacterConstant; - } - else - { - Value->Typ = &pc->IntType; - Value->Val->Integer = Result; - ResultToken = TokenIntegerConstant; - } + Value->Typ = &pc->LongType; /* ignored? */ + Value->Val->LongInteger = Result; + + ResultToken = TokenIntegerConstant; if (Lexer->Pos == Lexer->End) return ResultToken; - if (*Lexer->Pos == 'l' || *Lexer->Pos == 'L') +#ifndef NO_FP + if (Lexer->Pos == Lexer->End) { - LEXER_INC(Lexer); return ResultToken; } - -#ifndef NO_FP - if (Lexer->Pos == Lexer->End || *Lexer->Pos != '.') - return ResultToken; - - Value->Typ = &pc->FPType; - LEXER_INC(Lexer); - for (FPDiv = 1.0/Base, FPResult = (double)Result; Lexer->Pos != Lexer->End && IS_BASE_DIGIT(*Lexer->Pos, Base); LEXER_INC(Lexer), FPDiv /= (double)Base) - FPResult += GET_BASE_DIGIT(*Lexer->Pos) * FPDiv; + if (*Lexer->Pos != '.' && *Lexer->Pos != 'e' && *Lexer->Pos != 'E') + { + return ResultToken; + } + + Value->Typ = &pc->FPType; + FPResult = (double)Result; + + if (*Lexer->Pos == '.') + { + LEXER_INC(Lexer); + for (FPDiv = 1.0/Base; Lexer->Pos != Lexer->End && IS_BASE_DIGIT(*Lexer->Pos, Base); LEXER_INC(Lexer), FPDiv /= (double)Base) + { + FPResult += GET_BASE_DIGIT(*Lexer->Pos) * FPDiv; + } + } + if (Lexer->Pos != Lexer->End && (*Lexer->Pos == 'e' || *Lexer->Pos == 'E')) { - double ExponentMultiplier = 1.0; + int ExponentSign = 1; LEXER_INC(Lexer); if (Lexer->Pos != Lexer->End && *Lexer->Pos == '-') { - ExponentMultiplier = -1.0; + ExponentSign = -1; LEXER_INC(Lexer); } @@ -204,12 +220,15 @@ enum LexToken LexGetNumber(Picoc *pc, struct LexState *Lexer, struct Value *Valu Result = Result * Base + GET_BASE_DIGIT(*Lexer->Pos); LEXER_INC(Lexer); } - - FPResult *= pow((double)Base, (double)Result * ExponentMultiplier); + + FPResult *= pow((double)Base, (double)Result * ExponentSign); } Value->Val->FP = FPResult; - + + if (*Lexer->Pos == 'f' || *Lexer->Pos == 'F') + LEXER_INC(Lexer); + return TokenFPConstant; #else return ResultToken; @@ -496,7 +515,7 @@ int LexTokenSize(enum LexToken Token) switch (Token) { case TokenIdentifier: case TokenStringConstant: return sizeof(char *); - case TokenIntegerConstant: return sizeof(int); + case TokenIntegerConstant: return sizeof(long); case TokenCharacterConstant: return sizeof(unsigned char); case TokenFPConstant: return sizeof(double); default: return 0; @@ -523,7 +542,7 @@ void *LexTokenise(Picoc *pc, struct LexState *Lexer, int *TokenLen) { /* store the token at the end of the stack area */ Token = LexScanGetToken(pc, Lexer, &GotValue); - + #ifdef DEBUG_LEXER printf("Token: %02x\n", Token); #endif @@ -699,7 +718,7 @@ enum LexToken LexGetRawToken(struct ParseState *Parser, struct Value **Value, in { case TokenStringConstant: pc->LexValue.Typ = pc->CharPtrType; break; case TokenIdentifier: pc->LexValue.Typ = NULL; break; - case TokenIntegerConstant: pc->LexValue.Typ = &pc->IntType; break; + case TokenIntegerConstant: pc->LexValue.Typ = &pc->LongType; break; case TokenCharacterConstant: pc->LexValue.Typ = &pc->CharType; break; #ifndef NO_FP case TokenFPConstant: pc->LexValue.Typ = &pc->FPType; break; @@ -766,7 +785,7 @@ void LexHashIf(struct ParseState *Parser) { /* get symbol to check */ struct Value *IdentValue; - struct Value *SavedValue; + struct Value *SavedValue = NULL; struct ParseState MacroParser; enum LexToken Token = LexGetRawToken(Parser, &IdentValue, TRUE); @@ -783,7 +802,7 @@ void LexHashIf(struct ParseState *Parser) Token = LexGetRawToken(&MacroParser, &IdentValue, TRUE); } - if (Token != TokenCharacterConstant) + if (Token != TokenCharacterConstant && Token != TokenIntegerConstant) ProgramFail(Parser, "value expected"); /* is the identifier defined? */ @@ -823,6 +842,43 @@ void LexHashEndif(struct ParseState *Parser) Parser->HashIfEvaluateToLevel = Parser->HashIfLevel; } +#if 0 /* useful for debug */ +void LexPrintToken(enum LexToken Token) +{ + char* TokenNames[] = { + /* 0x00 */ "None", + /* 0x01 */ "Comma", + /* 0x02 */ "Assign", "AddAssign", "SubtractAssign", "MultiplyAssign", "DivideAssign", "ModulusAssign", + /* 0x08 */ "ShiftLeftAssign", "ShiftRightAssign", "ArithmeticAndAssign", "ArithmeticOrAssign", "ArithmeticExorAssign", + /* 0x0d */ "QuestionMark", "Colon", + /* 0x0f */ "LogicalOr", + /* 0x10 */ "LogicalAnd", + /* 0x11 */ "ArithmeticOr", + /* 0x12 */ "ArithmeticExor", + /* 0x13 */ "Ampersand", + /* 0x14 */ "Equal", "NotEqual", + /* 0x16 */ "LessThan", "GreaterThan", "LessEqual", "GreaterEqual", + /* 0x1a */ "ShiftLeft", "ShiftRight", + /* 0x1c */ "Plus", "Minus", + /* 0x1e */ "Asterisk", "Slash", "Modulus", + /* 0x21 */ "Increment", "Decrement", "UnaryNot", "UnaryExor", "Sizeof", "Cast", + /* 0x27 */ "LeftSquareBracket", "RightSquareBracket", "Dot", "Arrow", + /* 0x2b */ "OpenBracket", "CloseBracket", + /* 0x2d */ "Identifier", "IntegerConstant", "FPConstant", "StringConstant", "CharacterConstant", + /* 0x32 */ "Semicolon", "Ellipsis", + /* 0x34 */ "LeftBrace", "RightBrace", + /* 0x36 */ "IntType", "CharType", "FloatType", "DoubleType", "VoidType", "EnumType", + /* 0x3c */ "LongType", "SignedType", "ShortType", "StaticType", "AutoType", "RegisterType", "ExternType", "StructType", "UnionType", "UnsignedType", "Typedef", + /* 0x46 */ "Continue", "Do", "Else", "For", "Goto", "If", "While", "Break", "Switch", "Case", "Default", "Return", + /* 0x52 */ "HashDefine", "HashInclude", "HashIf", "HashIfdef", "HashIfndef", "HashElse", "HashEndif", + /* 0x59 */ "New", "Delete", + /* 0x5b */ "OpenMacroBracket", + /* 0x5c */ "EOF", "EndOfLine", "EndOfFunction" + }; + printf("{%s}", TokenNames[Token]); +} +#endif + /* get the next token given a parser state, pre-processing as we go */ enum LexToken LexGetToken(struct ParseState *Parser, struct Value **Value, int IncPos) { diff --git a/parse.c b/parse.c index 0f1a09a..32b182f 100644 --- a/parse.c +++ b/parse.c @@ -183,30 +183,86 @@ int ParseArrayInitialiser(struct ParseState *Parser, struct Value *NewVariable, ParserCopy(&CountParser, Parser); NumElements = ParseArrayInitialiser(&CountParser, NewVariable, FALSE); + + if (NewVariable->Typ->Base != TypeArray) + AssignFail(Parser, "%t from array initializer", NewVariable->Typ, NULL, 0, 0, NULL, 0); + if (NewVariable->Typ->ArraySize == 0) - VariableRealloc(Parser, NewVariable, NumElements); - - else if (NewVariable->Typ->ArraySize != NumElements) - AssignFail(Parser, "from an array of size %d to one of size %d", NULL, NULL, NumElements, NewVariable->Typ->ArraySize, NULL, 0); + { + NewVariable->Typ = TypeGetMatching(Parser->pc, Parser, NewVariable->Typ->FromType, NewVariable->Typ->Base, NumElements, NewVariable->Typ->Identifier, TRUE); + VariableRealloc(Parser, NewVariable, TypeSizeValue(NewVariable, FALSE)); + } + #ifdef DEBUG_ARRAY_INITIALIZER + PRINT_SOURCE_POS; + printf("array size: %d \n", NewVariable->Typ->ArraySize); + #endif } /* parse the array initialiser */ Token = LexGetToken(Parser, NULL, FALSE); while (Token != TokenRightBrace) { - struct Value *ArrayElement = NULL; - - if (Parser->Mode == RunModeRun && DoAssignment) - ArrayElement = VariableAllocValueFromExistingData(Parser, NewVariable->Typ->FromType, (union AnyValue *)(&NewVariable->Val->ArrayMem[0] + TypeSize(NewVariable->Typ->FromType, 0, TRUE) * ArrayIndex), TRUE, NewVariable); - - if (!ExpressionParse(Parser, &CValue)) - ProgramFail(Parser, "expression expected"); - - if (Parser->Mode == RunModeRun && DoAssignment) + if (LexGetToken(Parser, NULL, FALSE) == TokenLeftBrace) { - ExpressionAssign(Parser, ArrayElement, CValue, FALSE, NULL, 0, FALSE); - VariableStackPop(Parser, CValue); - VariableStackPop(Parser, ArrayElement); + /* this is a sub-array initialiser */ + int SubArraySize = 0; + struct Value *SubArray = NewVariable; + if (Parser->Mode == RunModeRun && DoAssignment) + { + SubArraySize = TypeSize(NewVariable->Typ->FromType, NewVariable->Typ->FromType->ArraySize, TRUE); + SubArray = VariableAllocValueFromExistingData(Parser, NewVariable->Typ->FromType, (union AnyValue *)(&NewVariable->Val->ArrayMem[0] + SubArraySize * ArrayIndex), TRUE, NewVariable); + #ifdef DEBUG_ARRAY_INITIALIZER + int FullArraySize = TypeSize(NewVariable->Typ, NewVariable->Typ->ArraySize, TRUE); + PRINT_SOURCE_POS; + PRINT_TYPE(NewVariable->Typ) + printf("[%d] subarray size: %d (full: %d,%d) \n", ArrayIndex, SubArraySize, FullArraySize, NewVariable->Typ->ArraySize); + #endif + if (ArrayIndex >= NewVariable->Typ->ArraySize) + ProgramFail(Parser, "too many array elements"); + } + LexGetToken(Parser, NULL, TRUE); + ParseArrayInitialiser(Parser, SubArray, DoAssignment); + } + else + { + struct Value *ArrayElement = NULL; + + if (Parser->Mode == RunModeRun && DoAssignment) + { + struct ValueType * ElementType = NewVariable->Typ; + int TotalSize = 1; + int ElementSize = 0; + + /* int x[3][3] = {1,2,3,4} => handle it just like int x[9] = {1,2,3,4} */ + while (ElementType->Base == TypeArray) + { + TotalSize *= ElementType->ArraySize; + ElementType = ElementType->FromType; + + /* char x[10][10] = {"abc", "def"} => assign "abc" to x[0], "def" to x[1] etc */ + if (LexGetToken(Parser, NULL, FALSE) == TokenStringConstant && ElementType->FromType->Base == TypeChar) + break; + } + ElementSize = TypeSize(ElementType, ElementType->ArraySize, TRUE); + #ifdef DEBUG_ARRAY_INITIALIZER + PRINT_SOURCE_POS; + printf("[%d/%d] element size: %d (x%d) \n", ArrayIndex, TotalSize, ElementSize, ElementType->ArraySize); + #endif + if (ArrayIndex >= TotalSize) + ProgramFail(Parser, "too many array elements"); + ArrayElement = VariableAllocValueFromExistingData(Parser, ElementType, (union AnyValue *)(&NewVariable->Val->ArrayMem[0] + ElementSize * ArrayIndex), TRUE, NewVariable); + } + + /* this is a normal expression initialiser */ + if (!ExpressionParse(Parser, &CValue)) + ProgramFail(Parser, "expression expected"); + + if (Parser->Mode == RunModeRun && DoAssignment) + { + ExpressionAssign(Parser, ArrayElement, CValue, FALSE, NULL, 0, FALSE); + VariableStackPop(Parser, CValue); + VariableStackPop(Parser, ArrayElement); + } } ArrayIndex++; @@ -393,8 +449,11 @@ void ParseFor(struct ParseState *Parser) struct ParseState PreIncrement; struct ParseState PreStatement; struct ParseState After; + enum RunMode OldMode = Parser->Mode; + int PrevScopeID = 0, ScopeID = VariableScopeBegin(Parser, &PrevScopeID); + if (LexGetToken(Parser, NULL, TRUE) != TokenOpenBracket) ProgramFail(Parser, "'(' expected"); @@ -420,7 +479,7 @@ void ParseFor(struct ParseState *Parser) if (ParseStatementMaybeRun(Parser, Condition, TRUE) != ParseResultOk) ProgramFail(Parser, "statement expected"); - if (Parser->Mode == RunModeContinue) + if (Parser->Mode == RunModeContinue && OldMode == RunModeRun) Parser->Mode = RunModeRun; ParserCopyPos(&After, Parser); @@ -448,16 +507,20 @@ void ParseFor(struct ParseState *Parser) if (Parser->Mode == RunModeBreak && OldMode == RunModeRun) Parser->Mode = RunModeRun; - + + VariableScopeEnd(Parser, ScopeID, PrevScopeID); + ParserCopyPos(Parser, &After); } /* parse a block of code and return what mode it returned in */ enum RunMode ParseBlock(struct ParseState *Parser, int AbsorbOpenBrace, int Condition) { + int PrevScopeID = 0, ScopeID = VariableScopeBegin(Parser, &PrevScopeID); + if (AbsorbOpenBrace && LexGetToken(Parser, NULL, TRUE) != TokenLeftBrace) ProgramFail(Parser, "'{' expected"); - + if (Parser->Mode == RunModeSkip || !Condition) { /* condition failed - skip this block instead */ @@ -476,7 +539,9 @@ enum RunMode ParseBlock(struct ParseState *Parser, int AbsorbOpenBrace, int Cond if (LexGetToken(Parser, NULL, TRUE) != TokenRightBrace) ProgramFail(Parser, "'}' expected"); - + + VariableScopeEnd(Parser, ScopeID, PrevScopeID); + return Parser->Mode; } @@ -548,6 +613,33 @@ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemi CheckTrailingSemicolon = FALSE; break; } +#ifdef FEATURE_AUTO_DECLARE_VARIABLES + else /* new_identifier = something */ + { /* try to guess type and declare the variable based on assigned value */ + if (NextToken == TokenAssign && !VariableDefinedAndOutOfScope(Parser->pc, LexerValue->Val->Identifier)) + { + if (Parser->Mode == RunModeRun) + { + struct Value *CValue; + char* Identifier = LexerValue->Val->Identifier; + + LexGetToken(Parser, NULL, TRUE); + if (!ExpressionParse(Parser, &CValue)) + { + ProgramFail(Parser, "expected: expression"); + } + + #if 0 + PRINT_SOURCE_POS; + PlatformPrintf(Parser->pc->CStdOut, "%t %s = %d;\n", CValue->Typ, Identifier, CValue->Val->Integer); + printf("%d\n", VariableDefined(Parser->pc, Identifier)); + #endif + VariableDefine(Parser->pc, Parser, Identifier, CValue, CValue->Typ, TRUE); + break; + } + } + } +#endif } /* else fallthrough to expression */ /* no break */ @@ -652,13 +744,9 @@ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemi break; case TokenFor: - { - enum RunMode OldMode = Parser->Mode; ParseFor(Parser); - Parser->Mode = OldMode; CheckTrailingSemicolon = FALSE; break; - } case TokenSemicolon: CheckTrailingSemicolon = FALSE; diff --git a/platform.c b/platform.c index bf40bf3..d6df722 100644 --- a/platform.c +++ b/platform.c @@ -170,8 +170,9 @@ void AssignFail(struct ParseState *Parser, const char *Format, struct ValueType if (FuncName != NULL) PlatformPrintf(Stream, " in argument %d of call to %s()", ParamNo, FuncName); - - ProgramFail(Parser, NULL, ""); + + PlatformPrintf(Stream, "\n"); + PlatformExit(Parser->pc, 1); } /* exit lexing with a message */ diff --git a/tests/59_break_before_loop.c b/tests/59_break_before_loop.c index 43780c5..2df59c7 100644 --- a/tests/59_break_before_loop.c +++ b/tests/59_break_before_loop.c @@ -43,5 +43,18 @@ int main() printf("a=%d\n",a); } + printf("\nTest 4\n"); + + a = 0; c = 0; + for (c=0;c<10;c++) + { + printf("c=%d\n",c); + foo(); + continue; + for (a = 0; a < 2; a++) + printf("a=%d\n",a); + printf("bar\n"); + } + return 0; } diff --git a/tests/59_break_before_loop.expect b/tests/59_break_before_loop.expect index 362e48b..269f08b 100644 --- a/tests/59_break_before_loop.expect +++ b/tests/59_break_before_loop.expect @@ -8,3 +8,25 @@ a=0 Test 3 c=0 foo + +Test 4 +c=0 +foo +c=1 +foo +c=2 +foo +c=3 +foo +c=4 +foo +c=5 +foo +c=6 +foo +c=7 +foo +c=8 +foo +c=9 +foo diff --git a/tests/Makefile b/tests/Makefile index a2d27b1..7c54a66 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -59,7 +59,7 @@ TESTS= 00_assignment.test \ 62_float.test \ 63_typedef.test \ 64_double_prefix_op.test \ - 65_typeless.test \ + #65_typeless.test \ include csmith/Makefile diff --git a/type.c b/type.c index 18fad9a..21e72db 100644 --- a/type.c +++ b/type.c @@ -121,11 +121,12 @@ void TypeInit(Picoc *pc) pc->UberType.DerivedTypeList = NULL; TypeAddBaseType(pc, &pc->IntType, TypeInt, sizeof(int), IntAlignBytes); TypeAddBaseType(pc, &pc->ShortType, TypeShort, sizeof(short), (char *)&sa.y - &sa.x); - TypeAddBaseType(pc, &pc->CharType, TypeChar, sizeof(unsigned char), (char *)&ca.y - &ca.x); + TypeAddBaseType(pc, &pc->CharType, TypeChar, sizeof(char), (char *)&ca.y - &ca.x); TypeAddBaseType(pc, &pc->LongType, TypeLong, sizeof(long), (char *)&la.y - &la.x); TypeAddBaseType(pc, &pc->UnsignedIntType, TypeUnsignedInt, sizeof(unsigned int), IntAlignBytes); TypeAddBaseType(pc, &pc->UnsignedShortType, TypeUnsignedShort, sizeof(unsigned short), (char *)&sa.y - &sa.x); TypeAddBaseType(pc, &pc->UnsignedLongType, TypeUnsignedLong, sizeof(unsigned long), (char *)&la.y - &la.x); + TypeAddBaseType(pc, &pc->UnsignedCharType, TypeUnsignedChar, sizeof(unsigned char), (char *)&ca.y - &ca.x); TypeAddBaseType(pc, &pc->VoidType, TypeVoid, 0, 1); TypeAddBaseType(pc, &pc->FunctionType, TypeFunction, sizeof(int), IntAlignBytes); TypeAddBaseType(pc, &pc->MacroType, TypeMacro, sizeof(int), IntAlignBytes); @@ -394,7 +395,7 @@ int TypeParseFront(struct ParseState *Parser, struct ValueType **Typ, int *IsSta { case TokenIntType: *Typ = Unsigned ? &pc->UnsignedIntType : &pc->IntType; break; case TokenShortType: *Typ = Unsigned ? &pc->UnsignedShortType : &pc->ShortType; break; - case TokenCharType: *Typ = &pc->CharType; break; + case TokenCharType: *Typ = Unsigned ? &pc->UnsignedCharType : &pc->CharType; break; case TokenLongType: *Typ = Unsigned ? &pc->UnsignedLongType : &pc->LongType; break; #ifndef NO_FP case TokenFloatType: case TokenDoubleType: *Typ = &pc->FPType; break; diff --git a/variable.c b/variable.c index d9de066..d2b6566 100644 --- a/variable.c +++ b/variable.c @@ -95,6 +95,10 @@ struct Value *VariableAllocValueAndData(Picoc *pc, struct ParseState *Parser, in NewValue->ValOnStack = !OnHeap; NewValue->IsLValue = IsLValue; NewValue->LValueFrom = LValueFrom; + if (Parser) + NewValue->ScopeID = Parser->ScopeID; + + NewValue->OutOfScope = 0; return NewValue; } @@ -158,10 +162,109 @@ void VariableRealloc(struct ParseState *Parser, struct Value *FromValue, int New FromValue->AnyValOnHeap = TRUE; } +int VariableScopeBegin(struct ParseState * Parser, int* OldScopeID) +{ + struct TableEntry *Entry; + struct TableEntry *NextEntry; + Picoc * pc = Parser->pc; + int Count; + #ifdef VAR_SCOPE_DEBUG + int FirstPrint = 0; + #endif + + struct Table * HashTable = (pc->TopStackFrame == NULL) ? &(pc->GlobalTable) : &(pc->TopStackFrame)->LocalTable; + + if (Parser->ScopeID == -1) return -1; + + /* XXX dumb hash, let's hope for no collisions... */ + *OldScopeID = Parser->ScopeID; + Parser->ScopeID = (int)(intptr_t)(Parser->SourceText) * ((int)(intptr_t)(Parser->Pos) / sizeof(char*)); + /* or maybe a more human-readable hash for debugging? */ + /* Parser->ScopeID = Parser->Line * 0x10000 + Parser->CharacterPos; */ + + for (Count = 0; Count < HashTable->Size; Count++) + { + for (Entry = HashTable->HashTable[Count]; Entry != NULL; Entry = NextEntry) + { + NextEntry = Entry->Next; + if (Entry->p.v.Val->ScopeID == Parser->ScopeID && Entry->p.v.Val->OutOfScope) + { + Entry->p.v.Val->OutOfScope = FALSE; + Entry->p.v.Key = (char*)((intptr_t)Entry->p.v.Key & ~1); + #ifdef VAR_SCOPE_DEBUG + if (!FirstPrint) { PRINT_SOURCE_POS; } + FirstPrint = 1; + printf(">>> back into scope: %s %x %d\n", Entry->p.v.Key, Entry->p.v.Val->ScopeID, Entry->p.v.Val->Val->Integer); + #endif + } + } + } + + return Parser->ScopeID; +} + +void VariableScopeEnd(struct ParseState * Parser, int ScopeID, int PrevScopeID) +{ + struct TableEntry *Entry; + struct TableEntry *NextEntry; + Picoc * pc = Parser->pc; + int Count; + #ifdef VAR_SCOPE_DEBUG + int FirstPrint = 0; + #endif + + struct Table * HashTable = (pc->TopStackFrame == NULL) ? &(pc->GlobalTable) : &(pc->TopStackFrame)->LocalTable; + + if (ScopeID == -1) return; + + for (Count = 0; Count < HashTable->Size; Count++) + { + for (Entry = HashTable->HashTable[Count]; Entry != NULL; Entry = NextEntry) + { + NextEntry = Entry->Next; + if (Entry->p.v.Val->ScopeID == ScopeID && !Entry->p.v.Val->OutOfScope) + { + #ifdef VAR_SCOPE_DEBUG + if (!FirstPrint) { PRINT_SOURCE_POS; } + FirstPrint = 1; + printf(">>> out of scope: %s %x %d\n", Entry->p.v.Key, Entry->p.v.Val->ScopeID, Entry->p.v.Val->Val->Integer); + #endif + Entry->p.v.Val->OutOfScope = TRUE; + Entry->p.v.Key = (char*)((intptr_t)Entry->p.v.Key | 1); /* alter the key so it won't be found by normal searches */ + } + } + } + + Parser->ScopeID = PrevScopeID; +} + +int VariableDefinedAndOutOfScope(Picoc * pc, const char* Ident) +{ + struct TableEntry *Entry; + int Count; + + struct Table * HashTable = (pc->TopStackFrame == NULL) ? &(pc->GlobalTable) : &(pc->TopStackFrame)->LocalTable; + for (Count = 0; Count < HashTable->Size; Count++) + { + for (Entry = HashTable->HashTable[Count]; Entry != NULL; Entry = Entry->Next) + { + if (Entry->p.v.Val->OutOfScope && (char*)((intptr_t)Entry->p.v.Key & ~1) == Ident) + return TRUE; + } + } + return FALSE; +} + /* define a variable. Ident must be registered */ struct Value *VariableDefine(Picoc *pc, struct ParseState *Parser, char *Ident, struct Value *InitValue, struct ValueType *Typ, int MakeWritable) { - struct Value *AssignValue; + struct Value * AssignValue; + struct Table * currentTable = (pc->TopStackFrame == NULL) ? &(pc->GlobalTable) : &(pc->TopStackFrame)->LocalTable; + + int ScopeID = Parser ? Parser->ScopeID : -1; +#ifdef VAR_SCOPE_DEBUG + if (Parser) fprintf(stderr, "def %s %x (%s:%d:%d)\n", Ident, ScopeID, Parser->FileName, Parser->Line, Parser->CharacterPos); +#endif if (InitValue != NULL) AssignValue = VariableAllocValueAndCopy(pc, Parser, InitValue, pc->TopStackFrame == NULL); @@ -169,8 +272,10 @@ struct Value *VariableDefine(Picoc *pc, struct ParseState *Parser, char *Ident, AssignValue = VariableAllocValueFromType(pc, Parser, Typ, MakeWritable, NULL, pc->TopStackFrame == NULL); AssignValue->IsLValue = MakeWritable; - - if (!TableSet(pc, (pc->TopStackFrame == NULL) ? &(pc->GlobalTable) : &(pc->TopStackFrame)->LocalTable, Ident, AssignValue, Parser ? ((char *)Parser->FileName) : NULL, Parser ? Parser->Line : 0, Parser ? Parser->CharacterPos : 0)) + AssignValue->ScopeID = ScopeID; + AssignValue->OutOfScope = FALSE; + + if (!TableSet(pc, currentTable, Ident, AssignValue, Parser ? ((char *)Parser->FileName) : NULL, Parser ? Parser->Line : 0, Parser ? Parser->CharacterPos : 0)) ProgramFail(Parser, "'%s' is already defined", Ident); return AssignValue; @@ -257,7 +362,12 @@ void VariableGet(Picoc *pc, struct ParseState *Parser, const char *Ident, struct if (pc->TopStackFrame == NULL || !TableGet(&pc->TopStackFrame->LocalTable, Ident, LVal, NULL, NULL, NULL)) { if (!TableGet(&pc->GlobalTable, Ident, LVal, NULL, NULL, NULL)) - ProgramFail(Parser, "'%s' is undefined", Ident); + { + if (VariableDefinedAndOutOfScope(pc, Ident)) + ProgramFail(Parser, "'%s' is out of scope", Ident); + else + ProgramFail(Parser, "'%s' is undefined", Ident); + } } }