// ---------------------------------------------------------------------------- // TLFunction::addContext // // Adds a [context] of the function // ---------------------------------------------------------------------------- void TLFunction::addContext( const string& context, const string& args, const string& return_type, string description, const string& deprecated_f) { contexts_.push_back(Context{ context, {}, return_type, description, "", "", "" }); auto& ctx = contexts_.back(); // Parse args Tokenizer tz; tz.setSpecialCharacters("[],"); tz.openString(args); vector<string> arg_tokens; while (true) { while (!tz.check(",")) { arg_tokens.push_back(tz.current().text); if (tz.atEnd()) break; tz.adv(); } ctx.params.push_back({}); ctx.params.back().parse(arg_tokens); arg_tokens.clear(); if (tz.atEnd()) break; tz.adv(); } if (!deprecated_f.empty()) { // Parse deprecated string tz.openString(deprecated_f); for (unsigned t = 0; t < 2; t++) { while (tz.check(",")) tz.adv(); bool is_replacement = true; for (unsigned c = 0; c < tz.current().text.size(); c++) { char chr = tz.current().text[c]; if (isdigit(chr) || chr == '.') { is_replacement = false; break; } } if (is_replacement) ctx.deprecated_f = tz.current().text; else ctx.deprecated_v = tz.current().text; if (tz.atEnd()) break; tz.adv(); } } }
// ----------------------------------------------------------------------------- // Parses ZMAPINFO-format definitions in [entry] // ----------------------------------------------------------------------------- bool MapInfo::parseZMapInfo(ArchiveEntry* entry) { Tokenizer tz; tz.setReadLowerCase(true); tz.openMem(entry->data(), entry->name()); while (!tz.atEnd()) { // Include if (tz.check("include")) { // Get entry at include path auto include_entry = entry->parent()->entryAtPath(tz.next().text); if (!include_entry) { Log::warning( "Warning - Parsing ZMapInfo \"{}\": Unable to include \"{}\" at line {}", entry->name(), tz.current().text, tz.lineNo()); } else if (!parseZMapInfo(include_entry)) return false; } // Map else if (tz.check("map") || tz.check("defaultmap") || tz.check("adddefaultmap")) { if (!parseZMap(tz, tz.current().text)) return false; } // DoomEdNums else if (tz.check("doomednums")) { if (!parseDoomEdNums(tz)) return false; } // Unknown block (skip it) else if (tz.check("{")) { Log::warning(2, "Warning - Parsing ZMapInfo \"{}\": Skipping {{}} block", entry->name()); tz.adv(); tz.skipSection("{", "}"); continue; } // Unknown else { Log::warning(2, R"(Warning - Parsing ZMapInfo "{}": Unknown token "{}")", entry->name(), tz.current().text); } tz.adv(); } Log::info(2, "Parsed ZMapInfo entry {} successfully", entry->name()); return true; } // ----------------------------------------------------------------------------- // Parses a ZMAPINFO map definition of [type] beginning at the current token in // tokenizer [tz] // ----------------------------------------------------------------------------- bool MapInfo::parseZMap(Tokenizer& tz, std::string_view type) { // TODO: Handle adddefaultmap auto map = default_map_; // Normal map, get lump/name/etc tz.adv(); if (type == "map") { // Entry name should be just after map keyword map.entry_name = tz.current().text; // Parse map name tz.adv(); if (tz.check("lookup")) { map.lookup_name = true; map.name = tz.next().text; } else { map.lookup_name = false; map.name = tz.current().text; } tz.adv(); } if (!tz.advIf("{")) { Log::error(R"(Error Parsing ZMapInfo: Expecting "{{", got "{}" at line {})", tz.current().text, tz.lineNo()); return false; } while (!tz.checkOrEnd("}")) { // Block (skip it) if (tz.advIf("{")) tz.skipSection("{", "}"); // LevelNum else if (tz.check("levelnum")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; // Parse number // TODO: Checks tz.next().toInt(map.level_num); } // Sky1 else if (tz.check("sky1")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; map.sky1 = tz.next().text; // Scroll speed // TODO: Checks if (tz.advIfNext(",")) tz.next().toFloat(map.sky1_scroll_speed); } // Sky2 else if (tz.check("sky2")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; map.sky2 = tz.next().text; // Scroll speed // TODO: Checks if (tz.advIfNext(",")) tz.next().toFloat(map.sky2_scroll_speed); } // Skybox else if (tz.check("skybox")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; map.sky1 = tz.next().text; } // DoubleSky else if (tz.check("doublesky")) map.sky_double = true; // ForceNoSkyStretch else if (tz.check("forcenoskystretch")) map.sky_force_no_stretch = true; // SkyStretch else if (tz.check("skystretch")) map.sky_stretch = true; // Fade else if (tz.check("fade")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; if (!strToCol(tz.next().text, map.fade)) return false; } // OutsideFog else if (tz.check("outsidefog")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; if (!strToCol(tz.next().text, map.fade_outside)) return false; } // EvenLighting else if (tz.check("evenlighting")) { map.lighting_wallshade_h = 0; map.lighting_wallshade_v = 0; } // SmoothLighting else if (tz.check("smoothlighting")) map.lighting_smooth = true; // VertWallShade else if (tz.check("vertwallshade")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; // TODO: Checks tz.next().toInt(map.lighting_wallshade_v); } // HorzWallShade else if (tz.check("horzwallshade")) { if (!checkEqualsToken(tz, "ZMapInfo")) return false; // TODO: Checks tz.next().toInt(map.lighting_wallshade_h); } // ForceFakeContrast else if (tz.check("forcefakecontrast")) map.force_fake_contrast = true; tz.adv(); }
/* MapSpecials::processACSScripts * Process 'OPEN' ACS scripts for various specials - sector colours, * slopes, etc. *******************************************************************/ void MapSpecials::processACSScripts(ArchiveEntry* entry) { sector_colours.clear(); sector_fadecolours.clear(); if (!entry || entry->getSize() == 0) return; Tokenizer tz; tz.setSpecialCharacters(";,:|={}/()"); tz.openMem(entry->getMCData(), "ACS Scripts"); while (!tz.atEnd()) { if (tz.checkNC("script")) { LOG_MESSAGE(3, "script found"); tz.adv(2); // Skip script # // Check for open script if (tz.checkNC("OPEN")) { LOG_MESSAGE(3, "script is OPEN"); // Skip to opening brace while (!tz.check("{")) tz.adv(); // Parse script while (!tz.checkOrEnd("}")) { // --- Sector_SetColor --- if (tz.checkNC("Sector_SetColor")) { // Get parameters auto parameters = tz.getTokensUntil(")"); // Parse parameters long val; int tag = -1; int r = -1; int g = -1; int b = -1; for (unsigned a = 0; a < parameters.size(); a++) { if (parameters[a].text.ToLong(&val)) { if (tag < 0) tag = val; else if (r < 0) r = val; else if (g < 0) g = val; else if (b < 0) b = val; } } // Check everything is set if (b < 0) { LOG_MESSAGE(2, "Invalid Sector_SetColor parameters"); } else { sector_colour_t sc; sc.tag = tag; sc.colour.set(r, g, b, 255); LOG_MESSAGE(3, "Sector tag %d, colour %d,%d,%d", tag, r, g, b); sector_colours.push_back(sc); } } // --- Sector_SetFade --- else if (tz.checkNC("Sector_SetFade")) { // Get parameters auto parameters = tz.getTokensUntil(")"); // Parse parameters long val; int tag = -1; int r = -1; int g = -1; int b = -1; for (unsigned a = 0; a < parameters.size(); a++) { if (parameters[a].text.ToLong(&val)) { if (tag < 0) tag = val; else if (r < 0) r = val; else if (g < 0) g = val; else if (b < 0) b = val; } } // Check everything is set if (b < 0) { LOG_MESSAGE(2, "Invalid Sector_SetFade parameters"); } else { sector_colour_t sc; sc.tag = tag; sc.colour.set(r, g, b, 0); LOG_MESSAGE(3, "Sector tag %d, fade colour %d,%d,%d", tag, r, g, b); sector_fadecolours.push_back(sc); } } tz.adv(); } } } tz.adv(); } }
// ----------------------------------------------------------------------------- // Parses a ZScript 'statement'. This isn't technically correct but suits our // purposes well enough // // tokens // { // block[0].tokens // { // block[0].block[0].tokens; // ... // } // // block[1].tokens; // ... // } // ----------------------------------------------------------------------------- bool ParsedStatement::parse(Tokenizer& tz) { // Check for unexpected token if (tz.check('}')) { tz.adv(); return false; } line = tz.lineNo(); // Tokens bool in_initializer = false; while (true) { // End of statement (;) if (tz.advIf(';')) return true; // DB comment if (tz.current().text.StartsWith(db_comment)) { tokens.push_back(tz.current().text); tokens.push_back(tz.getLine()); return true; } if (tz.check('}')) { // End of array initializer if (in_initializer) { in_initializer = false; tokens.emplace_back("}"); tz.adv(); continue; } // End of statement return true; } if (tz.atEnd()) { Log::debug(S_FMT("Failed parsing zscript statement/block beginning line %u", line)); return false; } // Beginning of block if (tz.advIf('{')) break; // Array initializer: ... = { ... } if (tz.current().text.Cmp("=") == 0 && tz.peek() == '{') { tokens.emplace_back("="); tokens.emplace_back("{"); tz.adv(2); in_initializer = true; continue; } tokens.push_back(tz.current().text); tz.adv(); } // Block while (true) { if (tz.advIf('}')) return true; if (tz.atEnd()) { Log::debug(S_FMT("Failed parsing zscript statement/block beginning line %u", line)); return false; } block.push_back({}); block.back().entry = entry; if (!block.back().parse(tz) || block.back().tokens.empty()) block.pop_back(); } }