Added "goto" statement.

git-svn-id: http://picoc.googlecode.com/svn/trunk@560 21eae674-98b7-11dd-bd71-f92a316d2d60
This commit is contained in:
zik.saleeba 2011-02-21 04:44:16 +00:00
parent ba05998a87
commit 3d7eaa7da6
9 changed files with 127 additions and 20 deletions

View file

@ -72,6 +72,7 @@ void PrintType(struct ValueType *Typ, IOFILE *Stream)
case TypeStruct: PrintStr("struct ", Stream); PrintStr(Typ->Identifier, Stream); break; case TypeStruct: PrintStr("struct ", Stream); PrintStr(Typ->Identifier, Stream); break;
case TypeUnion: PrintStr("union ", 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 TypeEnum: PrintStr("enum ", Stream); PrintStr(Typ->Identifier, Stream); break;
case TypeGotoLabel: PrintStr("goto label ", Stream); break;
case Type_Type: PrintStr("type ", Stream); break; case Type_Type: PrintStr("type ", Stream); break;
} }
} }

View file

@ -1433,9 +1433,15 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta
if (ParseStatement(&FuncParser, TRUE) != ParseResultOk) if (ParseStatement(&FuncParser, TRUE) != ParseResultOk)
ProgramFail(&FuncParser, "function body expected"); ProgramFail(&FuncParser, "function body expected");
if (FuncValue->Val->FuncDef.ReturnType != &VoidType && FuncParser.Mode == RunIt) 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); 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); VariableStackFramePop(Parser);
} }
else else

View file

@ -75,11 +75,11 @@ enum LexToken
/* 0x34 */ TokenLeftBrace, TokenRightBrace, /* 0x34 */ TokenLeftBrace, TokenRightBrace,
/* 0x36 */ TokenIntType, TokenCharType, TokenFloatType, TokenDoubleType, TokenVoidType, TokenEnumType, /* 0x36 */ TokenIntType, TokenCharType, TokenFloatType, TokenDoubleType, TokenVoidType, TokenEnumType,
/* 0x3c */ TokenLongType, TokenSignedType, TokenShortType, TokenStaticType, TokenAutoType, TokenRegisterType, TokenExternType, TokenStructType, TokenUnionType, TokenUnsignedType, TokenTypedef, /* 0x3c */ TokenLongType, TokenSignedType, TokenShortType, TokenStaticType, TokenAutoType, TokenRegisterType, TokenExternType, TokenStructType, TokenUnionType, TokenUnsignedType, TokenTypedef,
/* 0x46 */ TokenContinue, TokenDo, TokenElse, TokenFor, TokenIf, TokenWhile, TokenBreak, TokenSwitch, TokenCase, TokenDefault, TokenReturn, /* 0x46 */ TokenContinue, TokenDo, TokenElse, TokenFor, TokenGoto, TokenIf, TokenWhile, TokenBreak, TokenSwitch, TokenCase, TokenDefault, TokenReturn,
/* 0x51 */ TokenHashDefine, TokenHashInclude, TokenHashIf, TokenHashIfdef, TokenHashIfndef, TokenHashElse, TokenHashEndif, /* 0x52 */ TokenHashDefine, TokenHashInclude, TokenHashIf, TokenHashIfdef, TokenHashIfndef, TokenHashElse, TokenHashEndif,
/* 0x58 */ TokenNew, TokenDelete, /* 0x59 */ TokenNew, TokenDelete,
/* 0x5a */ TokenOpenMacroBracket, /* 0x5b */ TokenOpenMacroBracket,
/* 0x5b */ TokenEOF, TokenEndOfLine, TokenEndOfFunction /* 0x5c */ TokenEOF, TokenEndOfLine, TokenEndOfFunction
}; };
/* used in dynamic memory allocation */ /* used in dynamic memory allocation */
@ -97,7 +97,8 @@ enum RunMode
RunModeReturn, /* returning from a function */ RunModeReturn, /* returning from a function */
RunModeCaseSearch, /* searching for a case label */ RunModeCaseSearch, /* searching for a case label */
RunModeBreak, /* breaking out of a switch/while/do */ 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 */ /* parser state - has all this detail so we can parse nested files */
@ -109,6 +110,7 @@ struct ParseState
short int CharacterPos; short int CharacterPos;
enum RunMode Mode; /* whether to skip or run code */ enum RunMode Mode; /* whether to skip or run code */
int SearchLabel; /* what case label we're searching for */ int SearchLabel; /* what case label we're searching for */
const char *SearchGotoLabel;/* what goto label we're searching for */
short int HashIfLevel; short int HashIfLevel;
short int HashIfEvaluateToLevel; short int HashIfEvaluateToLevel;
const char *SourceText; const char *SourceText;
@ -135,6 +137,7 @@ enum BaseType
TypeStruct, /* aggregate type */ TypeStruct, /* aggregate type */
TypeUnion, /* merged type */ TypeUnion, /* merged type */
TypeEnum, /* enumerated integer type */ TypeEnum, /* enumerated integer type */
TypeGotoLabel, /* a label we can "goto" */
Type_Type /* a type for storing types */ Type_Type /* a type for storing types */
}; };
@ -311,6 +314,7 @@ extern struct ValueType VoidType;
extern struct ValueType TypeType; extern struct ValueType TypeType;
extern struct ValueType FunctionType; extern struct ValueType FunctionType;
extern struct ValueType MacroType; extern struct ValueType MacroType;
extern struct ValueType GotoLabelType;
extern struct ValueType *CharPtrType; extern struct ValueType *CharPtrType;
extern struct ValueType *CharPtrPtrType; extern struct ValueType *CharPtrPtrType;
extern struct ValueType *CharArrayType; extern struct ValueType *CharArrayType;

1
lex.c
View file

@ -62,6 +62,7 @@ static struct ReservedWord ReservedWords[] =
{ "float", TokenFloatType, NULL }, { "float", TokenFloatType, NULL },
#endif #endif
{ "for", TokenFor, NULL }, { "for", TokenFor, NULL },
{ "goto", TokenGoto, NULL },
{ "if", TokenIf, NULL }, { "if", TokenIf, NULL },
{ "int", TokenIntType, NULL }, { "int", TokenIntType, NULL },
{ "long", TokenLongType, NULL }, { "long", TokenLongType, NULL },

48
parse.c
View file

@ -80,7 +80,7 @@ struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueTyp
ProgramFail(Parser, "nested function definitions are not allowed"); ProgramFail(Parser, "nested function definitions are not allowed");
LexGetToken(Parser, NULL, TRUE); /* open bracket */ LexGetToken(Parser, NULL, TRUE); /* open bracket */
ParamParser = *Parser; ParserCopy(&ParamParser, Parser);
ParamCount = ParseCountParams(Parser); ParamCount = ParseCountParams(Parser);
if (ParamCount > PARAMETER_MAX) if (ParamCount > PARAMETER_MAX)
ProgramFail(Parser, "too many parameters"); ProgramFail(Parser, "too many parameters");
@ -150,7 +150,7 @@ struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueTyp
if (Token != TokenLeftBrace) if (Token != TokenLeftBrace)
ProgramFail(Parser, "bad function definition"); ProgramFail(Parser, "bad function definition");
FuncBody = *Parser; ParserCopy(&FuncBody, Parser);
if (ParseStatementMaybeRun(Parser, FALSE, TRUE) != ParseResultOk) if (ParseStatementMaybeRun(Parser, FALSE, TRUE) != ParseResultOk)
ProgramFail(Parser, "function definition expected"); ProgramFail(Parser, "function definition expected");
@ -261,7 +261,7 @@ int ParseDeclaration(struct ParseState *Parser, enum LexToken Token)
if (Typ == &VoidType && Identifier != StrEmpty) if (Typ == &VoidType && Identifier != StrEmpty)
ProgramFail(Parser, "can't define a void variable"); 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); NewVariable = VariableDefineButIgnoreIdentical(Parser, Identifier, Typ, IsStatic, &FirstVisit);
if (LexGetToken(Parser, NULL, FALSE) == TokenAssign) if (LexGetToken(Parser, NULL, FALSE) == TokenAssign)
@ -299,10 +299,12 @@ void ParseMacroDefinition(struct ParseState *Parser)
{ {
/* it's a parameterised macro, read the parameters */ /* it's a parameterised macro, read the parameters */
enum LexToken Token = LexGetToken(Parser, NULL, TRUE); enum LexToken Token = LexGetToken(Parser, NULL, TRUE);
struct ParseState ParamParser = *Parser; struct ParseState ParamParser;
int NumParams = ParseCountParams(&ParamParser); int NumParams;
int ParamCount = 0; int ParamCount = 0;
ParserCopy(&ParamParser, Parser);
NumParams = ParseCountParams(&ParamParser);
MacroValue = VariableAllocValueAndData(Parser, sizeof(struct MacroDef) + sizeof(const char *) * NumParams, FALSE, NULL, TRUE); MacroValue = VariableAllocValueAndData(Parser, sizeof(struct MacroDef) + sizeof(const char *) * NumParams, FALSE, NULL, TRUE);
MacroValue->Val->MacroDef.NumParams = NumParams; MacroValue->Val->MacroDef.NumParams = NumParams;
MacroValue->Val->MacroDef.ParamName = (char **)((char *)MacroValue->Val + sizeof(struct MacroDef)); 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 */ /* copy the body of the macro to execute later */
MacroValue->Val->MacroDef.Body = *Parser; ParserCopy(&MacroValue->Val->MacroDef.Body, Parser);
MacroValue->Typ = &MacroType; MacroValue->Typ = &MacroType;
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);
@ -479,8 +481,11 @@ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemi
struct Value *LexerValue; struct Value *LexerValue;
struct Value *VarValue; struct Value *VarValue;
int Condition; int Condition;
struct ParseState PreState = *Parser; struct ParseState PreState;
enum LexToken Token = LexGetToken(Parser, &LexerValue, TRUE); enum LexToken Token;
ParserCopy(&PreState, Parser);
Token = LexGetToken(Parser, &LexerValue, TRUE);
switch (Token) switch (Token)
{ {
@ -499,6 +504,21 @@ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemi
break; 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 */ /* else fallthrough to expression */
case TokenAsterisk: case TokenAsterisk:
@ -740,6 +760,18 @@ enum ParseResult ParseStatement(struct ParseState *Parser, int CheckTrailingSemi
ParseTypedef(Parser); ParseTypedef(Parser);
break; 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: case TokenDelete:
{ {
/* try it as a function or variable name to delete */ /* try it as a function or variable name to delete */

52
tests/54_goto.c Normal file
View file

@ -0,0 +1,52 @@
#include <stdio.h>
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();
}

8
tests/54_goto.expect Normal file
View file

@ -0,0 +1,8 @@
In fred()
At end
In joe()
c = 1234
done
In henry()
b = 1234
done

View file

@ -47,7 +47,8 @@ TESTS= 00_assignment.test \
49_bracket_evaluation.test \ 49_bracket_evaluation.test \
50_logical_second_arg.test \ 50_logical_second_arg.test \
51_static.test \ 51_static.test \
52_unnamed_enum.test 52_unnamed_enum.test \
54_goto.test
%.test: %.expect %.c %.test: %.expect %.c
@echo Test: $*... @echo Test: $*...

4
type.c
View file

@ -17,6 +17,7 @@ struct ValueType TypeType;
struct ValueType FunctionType; struct ValueType FunctionType;
struct ValueType MacroType; struct ValueType MacroType;
struct ValueType EnumType; struct ValueType EnumType;
struct ValueType GotoLabelType;
struct ValueType *CharPtrType; struct ValueType *CharPtrType;
struct ValueType *CharPtrPtrType; struct ValueType *CharPtrPtrType;
struct ValueType *CharArrayType; struct ValueType *CharArrayType;
@ -144,9 +145,10 @@ void TypeInit()
TypeAddBaseType(&UnsignedIntType, TypeUnsignedInt, sizeof(unsigned int), IntAlignBytes); TypeAddBaseType(&UnsignedIntType, TypeUnsignedInt, sizeof(unsigned int), IntAlignBytes);
TypeAddBaseType(&UnsignedShortType, TypeUnsignedShort, sizeof(unsigned short), (char *)&sa.y - &sa.x); TypeAddBaseType(&UnsignedShortType, TypeUnsignedShort, sizeof(unsigned short), (char *)&sa.y - &sa.x);
TypeAddBaseType(&UnsignedLongType, TypeUnsignedLong, sizeof(unsigned long), (char *)&la.y - &la.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(&FunctionType, TypeFunction, sizeof(int), IntAlignBytes);
TypeAddBaseType(&MacroType, TypeMacro, sizeof(int), IntAlignBytes); TypeAddBaseType(&MacroType, TypeMacro, sizeof(int), IntAlignBytes);
TypeAddBaseType(&GotoLabelType, TypeGotoLabel, 0, 1);
#ifndef NO_FP #ifndef NO_FP
TypeAddBaseType(&FPType, TypeFP, sizeof(double), (char *)&da.y - &da.x); 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 */ TypeAddBaseType(&TypeType, Type_Type, sizeof(double), (char *)&da.y - &da.x); /* must be large enough to cast to a double */