From 3d7eaa7da693ea15e4be5925d39c04fb61f05423 Mon Sep 17 00:00:00 2001 From: "zik.saleeba" Date: Mon, 21 Feb 2011 04:44:16 +0000 Subject: [PATCH] Added "goto" statement. git-svn-id: http://picoc.googlecode.com/svn/trunk@560 21eae674-98b7-11dd-bd71-f92a316d2d60 --- clibrary.c | 1 + expression.c | 10 +++++++-- interpreter.h | 16 +++++++++----- lex.c | 1 + parse.c | 48 +++++++++++++++++++++++++++++++++------- tests/54_goto.c | 52 ++++++++++++++++++++++++++++++++++++++++++++ tests/54_goto.expect | 8 +++++++ tests/Makefile | 7 +++--- type.c | 4 +++- 9 files changed, 127 insertions(+), 20 deletions(-) create mode 100644 tests/54_goto.c create mode 100644 tests/54_goto.expect diff --git a/clibrary.c b/clibrary.c index f4eb64b..8069dd3 100644 --- a/clibrary.c +++ b/clibrary.c @@ -72,6 +72,7 @@ void PrintType(struct ValueType *Typ, IOFILE *Stream) case TypeStruct: PrintStr("struct ", Stream); PrintStr(Typ->Identifier, Stream); break; case TypeUnion: PrintStr("union ", Stream); PrintStr(Typ->Identifier, Stream); break; case TypeEnum: PrintStr("enum ", Stream); PrintStr(Typ->Identifier, Stream); break; + case TypeGotoLabel: PrintStr("goto label ", Stream); break; case Type_Type: PrintStr("type ", Stream); break; } } diff --git a/expression.c b/expression.c index 237e991..f4a97b0 100644 --- a/expression.c +++ b/expression.c @@ -1433,9 +1433,15 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta if (ParseStatement(&FuncParser, TRUE) != ParseResultOk) ProgramFail(&FuncParser, "function body expected"); - if (FuncValue->Val->FuncDef.ReturnType != &VoidType && FuncParser.Mode == RunIt) - ProgramFail(&FuncParser, "no value returned from a function returning %t", FuncValue->Val->FuncDef.ReturnType); + if (RunIt) + { + if (FuncParser.Mode == RunModeRun && FuncValue->Val->FuncDef.ReturnType != &VoidType) + ProgramFail(&FuncParser, "no value returned from a function returning %t", FuncValue->Val->FuncDef.ReturnType); + else if (FuncParser.Mode == RunModeGoto) + ProgramFail(&FuncParser, "couldn't find goto label '%s'", FuncParser.SearchGotoLabel); + } + VariableStackFramePop(Parser); } else diff --git a/interpreter.h b/interpreter.h index ec0233f..2dcdb95 100644 --- a/interpreter.h +++ b/interpreter.h @@ -75,11 +75,11 @@ enum LexToken /* 0x34 */ TokenLeftBrace, TokenRightBrace, /* 0x36 */ TokenIntType, TokenCharType, TokenFloatType, TokenDoubleType, TokenVoidType, TokenEnumType, /* 0x3c */ TokenLongType, TokenSignedType, TokenShortType, TokenStaticType, TokenAutoType, TokenRegisterType, TokenExternType, TokenStructType, TokenUnionType, TokenUnsignedType, TokenTypedef, - /* 0x46 */ TokenContinue, TokenDo, TokenElse, TokenFor, TokenIf, TokenWhile, TokenBreak, TokenSwitch, TokenCase, TokenDefault, TokenReturn, - /* 0x51 */ TokenHashDefine, TokenHashInclude, TokenHashIf, TokenHashIfdef, TokenHashIfndef, TokenHashElse, TokenHashEndif, - /* 0x58 */ TokenNew, TokenDelete, - /* 0x5a */ TokenOpenMacroBracket, - /* 0x5b */ TokenEOF, TokenEndOfLine, TokenEndOfFunction + /* 0x46 */ TokenContinue, TokenDo, TokenElse, TokenFor, TokenGoto, TokenIf, TokenWhile, TokenBreak, TokenSwitch, TokenCase, TokenDefault, TokenReturn, + /* 0x52 */ TokenHashDefine, TokenHashInclude, TokenHashIf, TokenHashIfdef, TokenHashIfndef, TokenHashElse, TokenHashEndif, + /* 0x59 */ TokenNew, TokenDelete, + /* 0x5b */ TokenOpenMacroBracket, + /* 0x5c */ TokenEOF, TokenEndOfLine, TokenEndOfFunction }; /* used in dynamic memory allocation */ @@ -97,7 +97,8 @@ enum RunMode RunModeReturn, /* returning from a function */ RunModeCaseSearch, /* searching for a case label */ RunModeBreak, /* breaking out of a switch/while/do */ - RunModeContinue /* as above but repeat the loop */ + RunModeContinue, /* as above but repeat the loop */ + RunModeGoto /* searching for a goto label */ }; /* parser state - has all this detail so we can parse nested files */ @@ -109,6 +110,7 @@ struct ParseState short int CharacterPos; enum RunMode Mode; /* whether to skip or run code */ int SearchLabel; /* what case label we're searching for */ + const char *SearchGotoLabel;/* what goto label we're searching for */ short int HashIfLevel; short int HashIfEvaluateToLevel; const char *SourceText; @@ -135,6 +137,7 @@ enum BaseType TypeStruct, /* aggregate type */ TypeUnion, /* merged type */ TypeEnum, /* enumerated integer type */ + TypeGotoLabel, /* a label we can "goto" */ Type_Type /* a type for storing types */ }; @@ -311,6 +314,7 @@ extern struct ValueType VoidType; extern struct ValueType TypeType; extern struct ValueType FunctionType; extern struct ValueType MacroType; +extern struct ValueType GotoLabelType; extern struct ValueType *CharPtrType; extern struct ValueType *CharPtrPtrType; extern struct ValueType *CharArrayType; diff --git a/lex.c b/lex.c index c0d2f8f..f8bd28e 100644 --- a/lex.c +++ b/lex.c @@ -62,6 +62,7 @@ static struct ReservedWord ReservedWords[] = { "float", TokenFloatType, NULL }, #endif { "for", TokenFor, NULL }, + { "goto", TokenGoto, NULL }, { "if", TokenIf, NULL }, { "int", TokenIntType, NULL }, { "long", TokenLongType, NULL }, diff --git a/parse.c b/parse.c index c21a61d..f18b62d 100644 --- a/parse.c +++ b/parse.c @@ -80,7 +80,7 @@ struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueTyp ProgramFail(Parser, "nested function definitions are not allowed"); LexGetToken(Parser, NULL, TRUE); /* open bracket */ - ParamParser = *Parser; + ParserCopy(&ParamParser, Parser); ParamCount = ParseCountParams(Parser); if (ParamCount > PARAMETER_MAX) ProgramFail(Parser, "too many parameters"); @@ -150,7 +150,7 @@ struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueTyp if (Token != TokenLeftBrace) ProgramFail(Parser, "bad function definition"); - FuncBody = *Parser; + ParserCopy(&FuncBody, Parser); if (ParseStatementMaybeRun(Parser, FALSE, TRUE) != ParseResultOk) ProgramFail(Parser, "function definition expected"); @@ -261,7 +261,7 @@ int ParseDeclaration(struct ParseState *Parser, enum LexToken Token) if (Typ == &VoidType && Identifier != StrEmpty) ProgramFail(Parser, "can't define a void variable"); - if (Parser->Mode == RunModeRun) + if (Parser->Mode == RunModeRun || Parser->Mode == RunModeGoto) NewVariable = VariableDefineButIgnoreIdentical(Parser, Identifier, Typ, IsStatic, &FirstVisit); if (LexGetToken(Parser, NULL, FALSE) == TokenAssign) @@ -299,10 +299,12 @@ void ParseMacroDefinition(struct ParseState *Parser) { /* it's a parameterised macro, read the parameters */ enum LexToken Token = LexGetToken(Parser, NULL, TRUE); - struct ParseState ParamParser = *Parser; - int NumParams = ParseCountParams(&ParamParser); + struct ParseState ParamParser; + int NumParams; int ParamCount = 0; + ParserCopy(&ParamParser, Parser); + NumParams = ParseCountParams(&ParamParser); MacroValue = VariableAllocValueAndData(Parser, sizeof(struct MacroDef) + sizeof(const char *) * NumParams, FALSE, NULL, TRUE); MacroValue->Val->MacroDef.NumParams = NumParams; MacroValue->Val->MacroDef.ParamName = (char **)((char *)MacroValue->Val + sizeof(struct MacroDef)); @@ -334,7 +336,7 @@ void ParseMacroDefinition(struct ParseState *Parser) } /* copy the body of the macro to execute later */ - MacroValue->Val->MacroDef.Body = *Parser; + ParserCopy(&MacroValue->Val->MacroDef.Body, Parser); MacroValue->Typ = &MacroType; LexToEndOfLine(Parser); MacroValue->Val->MacroDef.Body.Pos = LexCopyTokens(&MacroValue->Val->MacroDef.Body, Parser); @@ -479,8 +481,11 @@ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemi struct Value *LexerValue; struct Value *VarValue; int Condition; - struct ParseState PreState = *Parser; - enum LexToken Token = LexGetToken(Parser, &LexerValue, TRUE); + struct ParseState PreState; + enum LexToken Token; + + ParserCopy(&PreState, Parser); + Token = LexGetToken(Parser, &LexerValue, TRUE); switch (Token) { @@ -499,6 +504,21 @@ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemi break; } } + else + { + /* it might be a goto label */ + enum LexToken NextToken = LexGetToken(Parser, NULL, FALSE); + if (NextToken == TokenColon) + { + /* declare the identifier as a goto label */ + LexGetToken(Parser, NULL, TRUE); + if (Parser->Mode == RunModeGoto && LexerValue->Val->Identifier == Parser->SearchGotoLabel) + Parser->Mode = RunModeRun; + + CheckTrailingSemicolon = FALSE; + break; + } + } /* else fallthrough to expression */ case TokenAsterisk: @@ -739,6 +759,18 @@ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemi case TokenTypedef: ParseTypedef(Parser); break; + + case TokenGoto: + if (LexGetToken(Parser, &LexerValue, TRUE) != TokenIdentifier) + ProgramFail(Parser, "identifier expected"); + + if (Parser->Mode == RunModeRun) + { + /* start scanning for the goto label */ + Parser->SearchGotoLabel = LexerValue->Val->Identifier; + Parser->Mode = RunModeGoto; + } + break; case TokenDelete: { diff --git a/tests/54_goto.c b/tests/54_goto.c new file mode 100644 index 0000000..65ee7e2 --- /dev/null +++ b/tests/54_goto.c @@ -0,0 +1,52 @@ +#include + +void fred() +{ + printf("In fred()\n"); + goto done; + printf("In middle\n"); +done: + printf("At end\n"); +} + +void joe() +{ + int b = 5678; + + printf("In joe()\n"); + + { + int c = 1234; + printf("c = %d\n", c); + goto outer; + printf("uh-oh\n"); + } + +outer: + + printf("done\n"); +} + +void henry() +{ + int a; + + printf("In henry()\n"); + goto inner; + + { + int b; +inner: + b = 1234; + printf("b = %d\n", b); + } + + printf("done\n"); +} + +void main() +{ + fred(); + joe(); + henry(); +} diff --git a/tests/54_goto.expect b/tests/54_goto.expect new file mode 100644 index 0000000..8e553fa --- /dev/null +++ b/tests/54_goto.expect @@ -0,0 +1,8 @@ +In fred() +At end +In joe() +c = 1234 +done +In henry() +b = 1234 +done diff --git a/tests/Makefile b/tests/Makefile index 4bc21b9..7b42f6f 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -31,10 +31,10 @@ TESTS= 00_assignment.test \ 31_args.test \ 32_led.test \ 33_ternary_op.test \ - 34_array_assignment.test \ + 34_array_assignment.test \ 35_sizeof.test \ 36_array_initialisers.test \ - 37_sprintf.test \ + 37_sprintf.test \ 38_multiple_array_index.test \ 39_typedef.test \ 40_stdio.test \ @@ -47,7 +47,8 @@ TESTS= 00_assignment.test \ 49_bracket_evaluation.test \ 50_logical_second_arg.test \ 51_static.test \ - 52_unnamed_enum.test + 52_unnamed_enum.test \ + 54_goto.test %.test: %.expect %.c @echo Test: $*... diff --git a/type.c b/type.c index 579da30..33464c5 100644 --- a/type.c +++ b/type.c @@ -17,6 +17,7 @@ struct ValueType TypeType; struct ValueType FunctionType; struct ValueType MacroType; struct ValueType EnumType; +struct ValueType GotoLabelType; struct ValueType *CharPtrType; struct ValueType *CharPtrPtrType; struct ValueType *CharArrayType; @@ -144,9 +145,10 @@ void TypeInit() TypeAddBaseType(&UnsignedIntType, TypeUnsignedInt, sizeof(unsigned int), IntAlignBytes); TypeAddBaseType(&UnsignedShortType, TypeUnsignedShort, sizeof(unsigned short), (char *)&sa.y - &sa.x); TypeAddBaseType(&UnsignedLongType, TypeUnsignedLong, sizeof(unsigned long), (char *)&la.y - &la.x); - TypeAddBaseType(&VoidType, TypeVoid, 0, 0); + TypeAddBaseType(&VoidType, TypeVoid, 0, 1); TypeAddBaseType(&FunctionType, TypeFunction, sizeof(int), IntAlignBytes); TypeAddBaseType(&MacroType, TypeMacro, sizeof(int), IntAlignBytes); + TypeAddBaseType(&GotoLabelType, TypeGotoLabel, 0, 1); #ifndef NO_FP TypeAddBaseType(&FPType, TypeFP, sizeof(double), (char *)&da.y - &da.x); TypeAddBaseType(&TypeType, Type_Type, sizeof(double), (char *)&da.y - &da.x); /* must be large enough to cast to a double */