Added "goto" statement.
git-svn-id: http://picoc.googlecode.com/svn/trunk@560 21eae674-98b7-11dd-bd71-f92a316d2d60
This commit is contained in:
parent
ba05998a87
commit
3d7eaa7da6
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
10
expression.c
10
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
|
||||
|
|
|
@ -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
1
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 },
|
||||
|
|
48
parse.c
48
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:
|
||||
{
|
||||
|
|
52
tests/54_goto.c
Normal file
52
tests/54_goto.c
Normal 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
8
tests/54_goto.expect
Normal file
|
@ -0,0 +1,8 @@
|
|||
In fred()
|
||||
At end
|
||||
In joe()
|
||||
c = 1234
|
||||
done
|
||||
In henry()
|
||||
b = 1234
|
||||
done
|
|
@ -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
4
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 */
|
||||
|
|
Loading…
Reference in a new issue