diff --git a/expression.c b/expression.c index 168826e..54ec890 100644 --- a/expression.c +++ b/expression.c @@ -1099,7 +1099,9 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result) ProgramFail(Parser, "identifier not expected here"); if (LexGetToken(Parser, NULL, FALSE) == TokenOpenBracket) + { ExpressionParseFunctionCall(Parser, &StackTop, LexValue->Val->Identifier); + } else { if (Parser->Mode == RunModeRun) @@ -1113,6 +1115,9 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result) struct ParseState MacroParser = VariableValue->Val->MacroDef.Body; struct Value *MacroResult; + if (VariableValue->Val->MacroDef.NumParams != 0) + ProgramFail(&MacroParser, "macro arguments missing"); + if (!ExpressionParse(&MacroParser, &MacroResult) || LexGetToken(&MacroParser, NULL, FALSE) != TokenEndOfFunction) ProgramFail(&MacroParser, "expression expected"); @@ -1195,6 +1200,83 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result) } +/* do a parameterised macro call */ +void ExpressionParseMacroCall(struct ParseState *Parser, struct ExpressionStack **StackTop, const char *MacroName, struct MacroDef *MDef) +{ + struct Value *ReturnValue = NULL; + struct Value *Param; + struct Value **ParamArray = NULL; + int ArgCount; + enum LexToken Token; + + if (Parser->Mode == RunModeRun) + { + /* create a stack frame for this macro */ + ExpressionStackPushValueByType(Parser, StackTop, &FPType); /* largest return type there is */ + ReturnValue = (*StackTop)->Val; + HeapPushStackFrame(); + ParamArray = HeapAllocStack(sizeof(struct Value *) * MDef->NumParams); + if (ParamArray == NULL) + ProgramFail(Parser, "out of memory"); + } + else + ExpressionPushInt(Parser, StackTop, 0); + + /* parse arguments */ + ArgCount = 0; + do { + if (ExpressionParse(Parser, &Param)) + { + if (Parser->Mode == RunModeRun) + { + if (ArgCount < MDef->NumParams) + ParamArray[ArgCount] = Param; + else + ProgramFail(Parser, "too many arguments to %s()", MacroName); + } + + ArgCount++; + Token = LexGetToken(Parser, NULL, TRUE); + if (Token != TokenComma && Token != TokenCloseBracket) + ProgramFail(Parser, "comma expected"); + } + else + { + /* end of argument list? */ + Token = LexGetToken(Parser, NULL, TRUE); + if (!TokenCloseBracket) + ProgramFail(Parser, "bad argument"); + } + + } while (Token != TokenCloseBracket); + + if (Parser->Mode == RunModeRun) + { + /* evaluate the macro */ + struct ParseState MacroParser; + int Count; + struct Value *EvalValue; + + if (ArgCount < MDef->NumParams) + ProgramFail(Parser, "not enough arguments to '%s'", MacroName); + + if (MDef->Body.Pos == NULL) + ProgramFail(Parser, "'%s' is undefined", MacroName); + + memcpy((void *)&MacroParser, (void *)&MDef->Body, sizeof(struct ParseState)); + VariableStackFrameAdd(Parser, 0); + TopStackFrame->NumParams = ArgCount; + TopStackFrame->ReturnValue = ReturnValue; + for (Count = 0; Count < MDef->NumParams; Count++) + VariableDefine(Parser, MDef->ParamName[Count], ParamArray[Count], NULL, TRUE); + + ExpressionParse(&MacroParser, &EvalValue); + ExpressionAssign(Parser, ReturnValue, EvalValue, TRUE, MacroName, 0, FALSE); + VariableStackFramePop(Parser); + HeapPopStackFrame(); + } +} + /* do a function call */ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionStack **StackTop, const char *FuncName) { @@ -1209,6 +1291,14 @@ void ExpressionParseFunctionCall(struct ParseState *Parser, struct ExpressionSta { /* get the function definition */ VariableGet(Parser, FuncName, &FuncValue); + + if (FuncValue->Typ->Base == TypeMacro) + { + /* this is actually a macro, not a function */ + ExpressionParseMacroCall(Parser, StackTop, FuncName, &FuncValue->Val->MacroDef); + return; + } + if (FuncValue->Typ->Base != TypeFunction) ProgramFail(Parser, "%t is not a function - can't call", FuncValue->Typ); diff --git a/lex.c b/lex.c index 89bf2d8..35d5bad 100644 --- a/lex.c +++ b/lex.c @@ -221,6 +221,9 @@ enum LexToken LexGetWord(struct LexState *Lexer, struct Value *Value) if (Token != TokenNone) return Token; + if (Lexer->Mode == LexModeHashDefineSpace) + Lexer->Mode = LexModeHashDefineSpaceIdent; + return TokenIdentifier; } @@ -383,7 +386,10 @@ enum LexToken LexScanGetToken(struct LexState *Lexer, struct Value **Value) #endif return TokenEndOfLine; } - else if (Lexer->Mode == LexModeHashDefine) + else if (Lexer->Mode == LexModeHashDefine || Lexer->Mode == LexModeHashDefineSpace) + Lexer->Mode = LexModeHashDefineSpace; + + else if (Lexer->Mode == LexModeHashDefineSpaceIdent) Lexer->Mode = LexModeNormal; LEXER_INC(Lexer); @@ -405,7 +411,7 @@ enum LexToken LexScanGetToken(struct LexState *Lexer, struct Value **Value) { case '"': GotToken = LexGetStringConstant(Lexer, *Value, '"'); break; case '\'': GotToken = LexGetCharacterConstant(Lexer, *Value); break; - case '(': if (Lexer->Mode == LexModeHashDefine) { GotToken = TokenOpenMacroBracket; Lexer->Mode = LexModeNormal; } else GotToken = TokenOpenBracket; break; + case '(': if (Lexer->Mode == LexModeHashDefineSpaceIdent) GotToken = TokenOpenMacroBracket; else GotToken = TokenOpenBracket; Lexer->Mode = LexModeNormal; break; case ')': GotToken = TokenCloseBracket; break; case '=': NEXTIS('=', TokenEqual, TokenAssign); break; case '+': NEXTIS3('=', TokenAddAssign, '+', TokenIncrement, TokenPlus); break; diff --git a/parse.c b/parse.c index 9cc8eb6..68800b0 100644 --- a/parse.c +++ b/parse.c @@ -242,12 +242,15 @@ int ParseDeclaration(struct ParseState *Parser, enum LexToken Token) void ParseMacroDefinition(struct ParseState *Parser) { struct Value *MacroName; + char *MacroNameStr; struct Value *ParamName; struct Value *MacroValue; if (LexGetToken(Parser, &MacroName, TRUE) != TokenIdentifier) ProgramFail(Parser, "identifier expected"); + MacroNameStr = MacroName->Val->Identifier; + if (LexGetToken(Parser, NULL, FALSE) == TokenOpenMacroBracket) { /* it's a parameterised macro, read the parameters */ @@ -258,6 +261,8 @@ void ParseMacroDefinition(struct ParseState *Parser) 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)); + Token = LexGetToken(Parser, &ParamName, TRUE); while (Token == TokenIdentifier) @@ -290,8 +295,8 @@ void ParseMacroDefinition(struct ParseState *Parser) LexToEndOfLine(Parser); MacroValue->Val->MacroDef.Body.Pos = LexCopyTokens(&MacroValue->Val->MacroDef.Body, Parser); - if (!TableSet(&GlobalTable, MacroName->Val->Identifier, MacroValue)) - ProgramFail(Parser, "'%s' is already defined", &MacroName->Val->Identifier); + if (!TableSet(&GlobalTable, MacroNameStr, MacroValue)) + ProgramFail(Parser, "'%s' is already defined", MacroNameStr); } /* copy where we're at in the parsing */ diff --git a/picoc.h b/picoc.h index 543e4d6..5905f02 100644 --- a/picoc.h +++ b/picoc.h @@ -242,7 +242,9 @@ enum LexMode { LexModeNormal, LexModeHashInclude, - LexModeHashDefine + LexModeHashDefine, + LexModeHashDefineSpace, + LexModeHashDefineSpaceIdent }; struct LexState diff --git a/tests/12_hashdefine.c b/tests/12_hashdefine.c index 680b87d..50e032a 100644 --- a/tests/12_hashdefine.c +++ b/tests/12_hashdefine.c @@ -4,5 +4,5 @@ #define BLOGGS(x) (12*(x)) printf("%d\n", FRED); -//printf("%d, %d, %d\n", BLOGGS(1), BLOGGS(2), BLOGGS(3)); +printf("%d, %d, %d\n", BLOGGS(1), BLOGGS(2), BLOGGS(3)); diff --git a/tests/12_hashdefine.expect b/tests/12_hashdefine.expect index 48082f7..99f2ed5 100644 --- a/tests/12_hashdefine.expect +++ b/tests/12_hashdefine.expect @@ -1 +1,2 @@ 12 +12, 24, 36 diff --git a/tests/33_ternary_op.c b/tests/33_ternary_op.c new file mode 100644 index 0000000..d36ac03 --- /dev/null +++ b/tests/33_ternary_op.c @@ -0,0 +1,8 @@ +#include + +int Count; + +for (Count = 0; Count < 10; Count++) +{ + printf("%d\n", (Count < 5) ? (Count*Count) : (Count * 3)); +} diff --git a/tests/33_ternary_op.expect b/tests/33_ternary_op.expect new file mode 100644 index 0000000..45ea507 --- /dev/null +++ b/tests/33_ternary_op.expect @@ -0,0 +1,10 @@ +0 +1 +4 +9 +16 +15 +18 +21 +24 +27