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 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;
}
}

View file

@ -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

View file

@ -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;

1
lex.c
View file

@ -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 },

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");
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:
{

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

@ -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: $*...

4
type.c
View file

@ -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 */