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 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
1
lex.c
|
@ -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
48
parse.c
|
@ -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
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
|
|
@ -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
4
type.c
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue