static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) { FScriptPosition scpos(sc); if (sc.CheckToken('(')) { FxExpression *data = ParseExpressionM (sc, cls); sc.MustGetToken(')'); return data; } else if (sc.CheckToken(TK_True)) { return new FxConstant(1, scpos); } else if (sc.CheckToken(TK_False)) { return new FxConstant(0, scpos); } else if (sc.CheckToken(TK_IntConst)) { return new FxConstant(sc.Number, scpos); } else if (sc.CheckToken(TK_FloatConst)) { return new FxConstant(sc.Float, scpos); } else if (sc.CheckToken(TK_NameConst)) { return new FxConstant(sc.Name, scpos); } else if (sc.CheckToken(TK_StringConst)) { // String parameters are converted to names. Technically, this should be // done at a higher level, as needed, but since no functions take string // arguments and ACS_NamedExecuteWithResult/CallACS need names, this is // a cheap way to get them working when people use "name" instead of 'name'. return new FxConstant(FName(sc.String), scpos); } else if (sc.CheckToken(TK_Identifier)) { FName identifier = FName(sc.String); FArgumentList *args; PFunction *func; switch (identifier) { case NAME_Random: case NAME_FRandom: return ParseRandom(sc, identifier, cls); case NAME_RandomPick: case NAME_FRandomPick: return ParseRandomPick(sc, identifier, cls); case NAME_Random2: return ParseRandom2(sc, cls); default: break; } if (sc.CheckToken('(')) { switch (identifier) { case NAME_Min: case NAME_Max: return ParseMinMax(sc, identifier, cls); case NAME_Clamp: return ParseClamp(sc, cls); case NAME_Abs: return ParseAbs(sc, cls); default: args = new FArgumentList; func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true)); try { // There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work. if (func != NULL && identifier != NAME_ACS_NamedExecuteWithResult) { sc.UnGet(); ParseFunctionParameters(sc, cls, *args, func, "", NULL); return new FxVMFunctionCall(func, args, sc); } else if (!sc.CheckToken(')')) { do { args->Push(ParseExpressionM (sc, cls)); } while (sc.CheckToken(',')); sc.MustGetToken(')'); } return new FxFunctionCall(NULL, identifier, args, sc); } catch (...) { delete args; throw; } break; } } else { return new FxIdentifier(identifier, sc); } } else { FString tokname = sc.TokenName(sc.TokenType, sc.String); sc.ScriptError ("Unexpected token %s", tokname.GetChars()); } return NULL; }
static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) { FScriptPosition scpos(sc); if (sc.CheckToken('(')) { FxExpression *data = ParseExpressionM (sc, cls); sc.MustGetToken(')'); return data; } else if (sc.CheckToken(TK_True)) { return new FxConstant(1, scpos); } else if (sc.CheckToken(TK_False)) { return new FxConstant(0, scpos); } else if (sc.CheckToken(TK_IntConst)) { return new FxConstant(sc.Number, scpos); } else if (sc.CheckToken(TK_FloatConst)) { return new FxConstant(sc.Float, scpos); } else if (sc.CheckToken(TK_NameConst)) { return new FxConstant(sc.Name, scpos); } else if (sc.CheckToken(TK_StringConst)) { // String parameters are converted to names. Technically, this should be // done at a higher level, as needed, but since no functions take string // arguments and ACS_NamedExecuteWithResult/CallACS need names, this is // a cheap way to get them working when people use "name" instead of 'name'. return new FxConstant(FName(sc.String), scpos); } else if (sc.CheckToken(TK_Random)) { FRandom *rng; if (sc.CheckToken('[')) { sc.MustGetToken(TK_Identifier); rng = FRandom::StaticFindRNG(sc.String); sc.MustGetToken(']'); } else { rng = &pr_exrandom; } sc.MustGetToken('('); FxExpression *min = ParseExpressionM (sc, cls); sc.MustGetToken(','); FxExpression *max = ParseExpressionM (sc, cls); sc.MustGetToken(')'); return new FxRandom(rng, min, max, sc); } else if (sc.CheckToken(TK_RandomPick) || sc.CheckToken(TK_FRandomPick)) { bool floaty = sc.TokenType == TK_FRandomPick; FRandom *rng; TArray<FxExpression*> list; list.Clear(); int index = 0; if (sc.CheckToken('[')) { sc.MustGetToken(TK_Identifier); rng = FRandom::StaticFindRNG(sc.String); sc.MustGetToken(']'); } else { rng = &pr_exrandom; } sc.MustGetToken('('); for (;;) { FxExpression *expr = ParseExpressionM(sc, cls); list.Push(expr); if (sc.CheckToken(')')) break; sc.MustGetToken(','); } return new FxRandomPick(rng, list, floaty, sc); } else if (sc.CheckToken(TK_FRandom)) { FRandom *rng; if (sc.CheckToken('[')) { sc.MustGetToken(TK_Identifier); rng = FRandom::StaticFindRNG(sc.String); sc.MustGetToken(']'); } else { rng = &pr_exrandom; } sc.MustGetToken('('); FxExpression *min = ParseExpressionM (sc, cls); sc.MustGetToken(','); FxExpression *max = ParseExpressionM (sc, cls); sc.MustGetToken(')'); return new FxFRandom(rng, min, max, sc); } else if (sc.CheckToken(TK_Random2)) { FRandom *rng; if (sc.CheckToken('[')) { sc.MustGetToken(TK_Identifier); rng = FRandom::StaticFindRNG(sc.String); sc.MustGetToken(']'); } else { rng = &pr_exrandom; } sc.MustGetToken('('); FxExpression *mask = NULL; if (!sc.CheckToken(')')) { mask = ParseExpressionM(sc, cls); sc.MustGetToken(')'); } return new FxRandom2(rng, mask, sc); } else if (sc.CheckToken(TK_Abs)) { sc.MustGetToken('('); FxExpression *x = ParseExpressionM (sc, cls); sc.MustGetToken(')'); return new FxAbs(x); } else if (sc.CheckToken(TK_Identifier)) { FName identifier = FName(sc.String); if (sc.CheckToken('(')) { FArgumentList *args = new FArgumentList; PFunction *func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(identifier, true)); try { if (func != NULL) { sc.UnGet(); ParseFunctionParameters(sc, cls, *args, func, "", NULL); return new FxVMFunctionCall(func, args, sc); } else if (!sc.CheckToken(')')) { do { args->Push(ParseExpressionM (sc, cls)); } while (sc.CheckToken(',')); sc.MustGetToken(')'); } return new FxFunctionCall(NULL, identifier, args, sc); } catch (...) { delete args; throw; } } else { return new FxIdentifier(identifier, sc); } } else { FString tokname = sc.TokenName(sc.TokenType, sc.String); sc.ScriptError ("Unexpected token %s", tokname.GetChars()); } return NULL; }