diff --git a/expression.c b/expression.c index 144735c..168826e 100644 --- a/expression.c +++ b/expression.c @@ -1110,7 +1110,7 @@ int ExpressionParse(struct ParseState *Parser, struct Value **Result) if (VariableValue->Typ->Base == TypeMacro) { /* evaluate a macro as a kind of simple subroutine */ - struct ParseState MacroParser = VariableValue->Val->Parser; + struct ParseState MacroParser = VariableValue->Val->MacroDef.Body; struct Value *MacroResult; if (!ExpressionParse(&MacroParser, &MacroResult) || LexGetToken(&MacroParser, NULL, FALSE) != TokenEndOfFunction) diff --git a/lex.c b/lex.c index 2a494f1..89bf2d8 100644 --- a/lex.c +++ b/lex.c @@ -211,8 +211,12 @@ enum LexToken LexGetWord(struct LexState *Lexer, struct Value *Value) Value->Val->Identifier = TableStrRegister2(StartPos, Lexer->Pos - StartPos); Token = LexCheckReservedWord(Value->Val->Identifier); - if (Token == TokenHashInclude) - Lexer->ScanningHashInclude = TRUE; + switch (Token) + { + case TokenHashInclude: Lexer->Mode = LexModeHashInclude; break; + case TokenHashDefine: Lexer->Mode = LexModeHashDefine; break; + default: break; + } if (Token != TokenNone) return Token; @@ -373,12 +377,14 @@ enum LexToken LexScanGetToken(struct LexState *Lexer, struct Value **Value) { Lexer->Line++; Lexer->Pos++; - Lexer->ScanningHashInclude = FALSE; + Lexer->Mode = LexModeNormal; #ifdef FANCY_ERROR_REPORTING Lexer->CharacterPos = 0; #endif return TokenEndOfLine; } + else if (Lexer->Mode == LexModeHashDefine) + Lexer->Mode = LexModeNormal; LEXER_INC(Lexer); } @@ -399,7 +405,7 @@ enum LexToken LexScanGetToken(struct LexState *Lexer, struct Value **Value) { case '"': GotToken = LexGetStringConstant(Lexer, *Value, '"'); break; case '\'': GotToken = LexGetCharacterConstant(Lexer, *Value); break; - case '(': GotToken = TokenOpenBracket; break; + case '(': if (Lexer->Mode == LexModeHashDefine) { GotToken = TokenOpenMacroBracket; Lexer->Mode = LexModeNormal; } else GotToken = TokenOpenBracket; break; case ')': GotToken = TokenCloseBracket; break; case '=': NEXTIS('=', TokenEqual, TokenAssign); break; case '+': NEXTIS3('=', TokenAddAssign, '+', TokenIncrement, TokenPlus); break; @@ -407,7 +413,7 @@ enum LexToken LexScanGetToken(struct LexState *Lexer, struct Value **Value) case '*': NEXTIS('=', TokenMultiplyAssign, TokenAsterisk); break; case '/': if (NextChar == '/' || NextChar == '*') LexSkipComment(Lexer, NextChar); else NEXTIS('=', TokenDivideAssign, TokenSlash); break; case '%': NEXTIS('=', TokenModulusAssign, TokenModulus); break; - case '<': if (Lexer->ScanningHashInclude) GotToken = LexGetStringConstant(Lexer, *Value, '>'); else { NEXTIS3PLUS('=', TokenLessEqual, '<', TokenShiftLeft, '=', TokenShiftLeftAssign, TokenLessThan); } break; + case '<': if (Lexer->Mode == LexModeHashInclude) GotToken = LexGetStringConstant(Lexer, *Value, '>'); else { NEXTIS3PLUS('=', TokenLessEqual, '<', TokenShiftLeft, '=', TokenShiftLeftAssign, TokenLessThan); } break; case '>': NEXTIS3PLUS('=', TokenGreaterEqual, '>', TokenShiftRight, '=', TokenShiftRightAssign, TokenGreaterThan); break; case ';': GotToken = TokenSemicolon; break; case '&': NEXTIS3('=', TokenArithmeticAndAssign, '&', TokenLogicalAnd, TokenAmpersand); break; @@ -528,7 +534,7 @@ void *LexAnalyse(const char *FileName, const char *Source, int SourceLen, int *T Lexer.End = Source + SourceLen; Lexer.Line = 1; Lexer.FileName = FileName; - Lexer.ScanningHashInclude = FALSE; + Lexer.Mode = LexModeNormal; #ifdef FANCY_ERROR_REPORTING Lexer.CharacterPos = 1; Lexer.SourceText = Source; diff --git a/parse.c b/parse.c index 69ea1f1..9cc8eb6 100644 --- a/parse.c +++ b/parse.c @@ -26,24 +26,12 @@ enum ParseResult ParseStatementMaybeRun(struct ParseState *Parser, int Condition return ParseStatement(Parser, CheckTrailingSemicolon); } -/* parse a function definition and store it for later */ -struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueType *ReturnType, char *Identifier) +/* count the number of parameters to a function or macro */ +int ParseCountParams(struct ParseState *Parser) { - struct ValueType *ParamType; - char *ParamIdentifier; - enum LexToken Token; - struct Value *FuncValue; - struct Value *OldFuncValue; - struct ParseState ParamParser; - struct ParseState FuncBody; int ParamCount = 0; - - if (TopStackFrame != NULL) - ProgramFail(Parser, "nested function definitions are not allowed"); - - LexGetToken(Parser, NULL, TRUE); /* open bracket */ - ParamParser = *Parser; - Token = LexGetToken(Parser, NULL, TRUE); + + enum LexToken Token = LexGetToken(Parser, NULL, TRUE); if (Token != TokenCloseBracket && Token != TokenEOF) { /* count the number of parameters */ @@ -54,6 +42,28 @@ struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueTyp ParamCount++; } } + + return ParamCount; +} + +/* parse a function definition and store it for later */ +struct Value *ParseFunctionDefinition(struct ParseState *Parser, struct ValueType *ReturnType, char *Identifier) +{ + struct ValueType *ParamType; + char *ParamIdentifier; + enum LexToken Token; + struct ParseState ParamParser; + struct Value *FuncValue; + struct Value *OldFuncValue; + struct ParseState FuncBody; + int ParamCount = 0; + + if (TopStackFrame != NULL) + ProgramFail(Parser, "nested function definitions are not allowed"); + + LexGetToken(Parser, NULL, TRUE); /* open bracket */ + ParamParser = *Parser; + ParamCount = ParseCountParams(Parser); if (ParamCount > PARAMETER_MAX) ProgramFail(Parser, "too many parameters"); @@ -232,15 +242,53 @@ int ParseDeclaration(struct ParseState *Parser, enum LexToken Token) void ParseMacroDefinition(struct ParseState *Parser) { struct Value *MacroName; - struct Value *MacroValue = VariableAllocValueAndData(Parser, sizeof(struct ParseState), FALSE, NULL, TRUE); + struct Value *ParamName; + struct Value *MacroValue; if (LexGetToken(Parser, &MacroName, TRUE) != TokenIdentifier) ProgramFail(Parser, "identifier expected"); - MacroValue->Val->Parser = *Parser; + if (LexGetToken(Parser, NULL, FALSE) == TokenOpenMacroBracket) + { + /* it's a parameterised macro, read the parameters */ + enum LexToken Token = LexGetToken(Parser, NULL, TRUE); + struct ParseState ParamParser = *Parser; + int NumParams = ParseCountParams(&ParamParser); + int ParamCount = 0; + + MacroValue = VariableAllocValueAndData(Parser, sizeof(struct MacroDef) + sizeof(const char *) * NumParams, FALSE, NULL, TRUE); + MacroValue->Val->MacroDef.NumParams = NumParams; + Token = LexGetToken(Parser, &ParamName, TRUE); + + while (Token == TokenIdentifier) + { + /* store a parameter name */ + MacroValue->Val->MacroDef.ParamName[ParamCount++] = ParamName->Val->Identifier; + + /* get the trailing comma */ + Token = LexGetToken(Parser, NULL, TRUE); + if (Token == TokenComma) + Token = LexGetToken(Parser, &ParamName, TRUE); + + else if (Token != TokenCloseBracket) + ProgramFail(Parser, "comma expected"); + } + + if (Token != TokenCloseBracket) + ProgramFail(Parser, "close bracket expected"); + } + else + { + /* allocate a simple unparameterised macro */ + MacroValue = VariableAllocValueAndData(Parser, sizeof(struct MacroDef), FALSE, NULL, TRUE); + MacroValue->Val->MacroDef.NumParams = 0; + } + + /* copy the body of the macro to execute later */ + MacroValue->Val->MacroDef.Body = *Parser; MacroValue->Typ = &MacroType; LexToEndOfLine(Parser); - MacroValue->Val->Parser.Pos = LexCopyTokens(&MacroValue->Val->Parser, 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); diff --git a/picoc.h b/picoc.h index 7a73b9a..543e4d6 100644 --- a/picoc.h +++ b/picoc.h @@ -76,7 +76,8 @@ enum LexToken /* 0x3c */ TokenLongType, TokenSignedType, TokenShortType, TokenStructType, TokenUnionType, TokenUnsignedType, TokenTypedef, /* 0x43 */ TokenContinue, TokenDo, TokenElse, TokenFor, TokenIf, TokenWhile, TokenBreak, TokenSwitch, TokenCase, TokenDefault, TokenReturn, /* 0x4e */ TokenHashDefine, TokenHashInclude, TokenNew, TokenDelete, - /* 0x52 */ TokenEOF, TokenEndOfLine, TokenEndOfFunction + /* 0x52 */ TokenOpenMacroBracket, + /* 0x53 */ TokenEOF, TokenEndOfLine, TokenEndOfFunction }; /* used in dynamic memory allocation */ @@ -161,6 +162,14 @@ struct FuncDef struct ParseState Body; /* lexical tokens of the function body if not intrinsic */ }; +/* macro definition */ +struct MacroDef +{ + int NumParams; /* the number of parameters */ + char **ParamName; /* array of parameter names */ + struct ParseState Body; /* lexical tokens of the function body if not intrinsic */ +}; + /* values */ union AnyValue { @@ -173,13 +182,14 @@ union AnyValue unsigned long UnsignedLongInteger; char *Identifier; char ArrayMem[2]; /* placeholder for where the data starts, doesn't point to it */ - struct ParseState Parser; +/* struct ParseState Parser; */ struct ValueType *Typ; struct FuncDef FuncDef; + struct MacroDef MacroDef; #ifndef NO_FP double FP; #endif - void *Pointer; /* unsafe native pointers */ + void *Pointer; /* unsafe native pointers */ }; struct Value @@ -228,13 +238,20 @@ struct StackFrame }; /* lexer state */ +enum LexMode +{ + LexModeNormal, + LexModeHashInclude, + LexModeHashDefine +}; + struct LexState { const char *Pos; const char *End; const char *FileName; int Line; - int ScanningHashInclude; + enum LexMode Mode; #ifdef FANCY_ERROR_REPORTING int CharacterPos; const char *SourceText; diff --git a/variable.c b/variable.c index f61c596..37d93bd 100644 --- a/variable.c +++ b/variable.c @@ -34,7 +34,7 @@ void VariableFree(struct Value *Val) /* free macro bodies */ if (Val->Typ == &MacroType) - HeapFreeMem((void *)Val->Val->Parser.Pos); + HeapFreeMem((void *)Val->Val->MacroDef.Body.Pos); /* free the value */ HeapFreeMem(Val);