示例#1
0
/* TextEditor::openJumpToDialog
 * Initialises and opens the 'Jump To' dialog
 *******************************************************************/
void TextEditor::openJumpToDialog()
{
	// Can't do this without a language definition or defined blocks
	if (!language || language->nJumpBlocks() == 0)
		return;

	// --- Scan for functions/scripts ---
	Tokenizer tz;
	vector<jp_t> jump_points;
	tz.openString(GetText());

	string token = tz.getToken();
	while (!token.IsEmpty())
	{
		if (token == "{")
		{
			// Skip block
			while (!token.IsEmpty() && token != "}")
				token = tz.getToken();
		}

		for (unsigned a = 0; a < language->nJumpBlocks(); a++)
		{
			// Get jump block keyword
			string block = language->jumpBlock(a);
			long skip = 0;
			if (block.Contains(":"))
			{
				wxArrayString sp = wxSplit(block, ':');
				sp.back().ToLong(&skip);
				block = sp[0];
			}

			if (S_CMPNOCASE(token, block))
			{
				string name = tz.getToken();
				for (int s = 0; s < skip; s++)
					name = tz.getToken();

				for (unsigned i = 0; i < language->nJBIgnore(); ++i)
					if (S_CMPNOCASE(name, language->jBIgnore(i)))
						name = tz.getToken();

				// Numbered block, add block name
				if (name.IsNumber())
					name = S_FMT("%s %s", language->jumpBlock(a), name);
				// Unnamed block, use block name
				if (name == "{" || name == ";")
					name = language->jumpBlock(a);

				// Create jump point
				jp_t jp;
				jp.name = name;
				jp.line = tz.lineNo() - 1;
				jump_points.push_back(jp);
			}
		}

		token = tz.getToken();
	}

	// Do nothing if no jump points
	if (jump_points.size() == 0)
		return;


	// --- Setup/show dialog ---
	wxDialog dlg(this, -1, "Jump To...");
	wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
	dlg.SetSizer(sizer);

	// Add Jump to dropdown
	wxChoice* choice_jump_to = new wxChoice(&dlg, -1);
	sizer->Add(choice_jump_to, 0, wxEXPAND|wxALL, 4);
	for (unsigned a = 0; a < jump_points.size(); a++)
		choice_jump_to->Append(jump_points[a].name);
	choice_jump_to->SetSelection(0);

	// Add dialog buttons
	sizer->Add(dlg.CreateButtonSizer(wxOK|wxCANCEL), 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 4);

	// Show dialog
	dlg.SetInitialSize(wxSize(250, -1));
	dlg.CenterOnParent();
	if (dlg.ShowModal() == wxID_OK)
	{
		int selection = choice_jump_to->GetSelection();
		if (selection >= 0 && selection < (int)jump_points.size())
		{
			// Get line number
			int line = jump_points[selection].line;

			// Move to line
			int pos = GetLineEndPosition(line);
			SetCurrentPos(pos);
			SetSelection(pos, pos);
			SetFirstVisibleLine(line);
			SetFocus();
		}
	}
}
示例#2
0
文件: Parser.cpp 项目: Zekom/SLADE
/* ParseTreeNode::parse
 * Parses formatted text data. Current valid formatting is:
 * (type) child = value;
 * (type) child = value1, value2, ...;
 * (type) child = { value1, value2, ... }
 * (type) child { grandchild = value; etc... }
 * (type) child : inherited { ... }
 * All values are read as strings, but can be retrieved as string,
 * int, bool or float.
 *******************************************************************/
bool ParseTreeNode::parse(Tokenizer& tz)
{
    // Get first token
    string token = tz.getToken();

    // Keep parsing until final } is reached (or end of file)
    while (!(S_CMP(token, "}")) && !token.IsEmpty())
    {
        // Check for preprocessor stuff
        if (parser)
        {
            // #define
            if (S_CMPNOCASE(token, "#define"))
            {
                parser->define(tz.getToken());
                token = tz.getToken();
                continue;
            }

            // #if(n)def
            if (S_CMPNOCASE(token, "#ifdef") || S_CMPNOCASE(token, "#ifndef"))
            {
                bool test = true;
                if (S_CMPNOCASE(token, "#ifndef"))
                    test = false;
                string define = tz.getToken();
                if (parser->defined(define) == test)
                {
                    // Continue
                    token = tz.getToken();
                    continue;
                }
                else
                {
                    // Skip section
                    int skip = 0;
                    while (true)
                    {
                        token = tz.getToken();
                        if (S_CMPNOCASE(token, "#endif"))
                            skip--;
                        else if (S_CMPNOCASE(token, "#ifdef"))
                            skip++;
                        else if (S_CMPNOCASE(token, "#ifndef"))
                            skip++;

                        if (skip < 0)
                            break;
                        if (token.IsEmpty())
                        {
                            wxLogMessage("Error: found end of file within #if(n)def block");
                            break;
                        }
                    }

                    continue;
                }
            }

            // #include (ignore)
            if (S_CMPNOCASE(token, "#include"))
            {
                tz.skipToken();	// Skip include path
                token = tz.getToken();
                continue;
            }

            // #endif (ignore)
            if (S_CMPNOCASE(token, "#endif"))
            {
                token = tz.getToken();
                continue;
            }
        }

        // If it's a special character (ie not a valid name), parsing fails
        if (tz.isSpecialCharacter(token.at(0)))
        {
            wxLogMessage("Parsing error: Unexpected special character '%s' in %s (line %d)", CHR(token), CHR(tz.getName()), tz.lineNo());
            return false;
        }

        // So we have either a node or property name
        string name = token;

        // Check next token to determine what we're doing
        string next = tz.peekToken();

        // Check for type+name pair
        string type = "";
        if (next != "=" && next != "{" && next != ";" && next != ":")
        {
            type = name;
            name = tz.getToken();
            next = tz.peekToken();
        }

        // Assignment
        if (S_CMP(next, "="))
        {
            // Skip =
            tz.skipToken();

            // Create item node
            ParseTreeNode* child = (ParseTreeNode*)addChild(name);
            child->type = type;

            // Check type of assignment list
            token = tz.getToken();
            string list_end = ";";
            if (token == "{")
            {
                list_end = "}";
                token = tz.getToken();
            }

            // Parse until ; or }
            while (1)
            {
                // Check for list end
                if (S_CMP(token, list_end) && !tz.quotedString())
                    break;

                // Setup value
                Property value;

                // Detect value type
                if (tz.quotedString())					// Quoted string
                    value = token;
                else if (S_CMPNOCASE(token, "true"))	// Boolean (true)
                    value = true;
                else if (S_CMPNOCASE(token, "false"))	// Boolean (false)
                    value = false;
                else if (re_int1.Matches(token) ||		// Integer
                         re_int2.Matches(token))
                {
                    long val;
                    token.ToLong(&val);
                    value = (int)val;
                }
                else if (re_int3.Matches(token))  		// Hex (0xXXXXXX)
                {
                    long val;
                    token.ToLong(&val, 0);
                    value = (int)val;
                    //wxLogMessage("%s: %s is hex %d", CHR(name), CHR(token), value.getIntValue());
                }
                else if (re_float.Matches(token))  		// Floating point
                {
                    double val;
                    token.ToDouble(&val);
                    value = (double)val;
                    //LOG_MESSAGE(3, S_FMT("%s: %s is float %1.3f", CHR(name), CHR(token), val));
                }
                else									// Unknown, just treat as string
                    value = token;

                // Add value
                child->values.push_back(value);

                // Check for ,
                if (S_CMP(tz.peekToken(), ","))
                    tz.skipToken();	// Skip it
                else if (!(S_CMP(tz.peekToken(), list_end)))
                {
                    string t = tz.getToken();
                    string n = tz.getName();
                    wxLogMessage("Parsing error: Expected \",\" or \"%s\", got \"%s\" in %s (line %d)", CHR(list_end), CHR(t), CHR(n), tz.lineNo());
                    return false;
                }

                token = tz.getToken();
            }
        }

        // Child node
        else if (S_CMP(next, "{"))
        {
            // Add child node
            ParseTreeNode* child = (ParseTreeNode*)addChild(name);
            child->type = type;

            // Skip {
            tz.skipToken();

            // Parse child node
            if (!child->parse(tz))
                return false;
        }

        // Child node (with no values/children)
        else if (S_CMP(next, ";"))
        {
            // Add child node
            ParseTreeNode* child = (ParseTreeNode*)addChild(name);
            child->type = type;

            // Skip ;
            tz.skipToken();
        }

        // Child node + inheritance
        else if (S_CMP(next, ":"))
        {
            // Skip :
            tz.skipToken();

            // Read inherited name
            string inherit = tz.getToken();

            // Check for opening brace
            if (tz.checkToken("{"))
            {
                // Add child node
                ParseTreeNode* child = (ParseTreeNode*)addChild(name);
                child->type = type;

                // Set its inheritance
                child->inherit = inherit;

                // Parse child node
                if (!child->parse(tz))
                    return false;
            }
        }

        // Unexpected token
        else
        {
            wxLogMessage("Parsing error: \"%s\" unexpected in %s (line %d)", CHR(next), CHR(tz.getName()), tz.lineNo());
            return false;
        }

        // Continue parsing
        token = tz.getToken();
    }

    return true;
}
示例#3
0
// -----------------------------------------------------------------------------
// 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();
	}
示例#4
0
// -----------------------------------------------------------------------------
// Returns true if the next token in [tz] is '='. If not, logs an error message
// -----------------------------------------------------------------------------
bool MapInfo::checkEqualsToken(Tokenizer& tz, std::string_view parsing) const
{
	if (tz.next() != "=")
	{
		Log::error("Error Parsing {}: Expected \"=\", got \"{}\" at line {}", parsing, tz.current().text, tz.lineNo());
		return false;
	}

	return true;
}
示例#5
0
/* JumpToCalculator::Entry
 * JumpToCalculator thread entry function
 *******************************************************************/
wxThread::ExitCode JumpToCalculator::Entry()
{
	string jump_points;

	Tokenizer tz;
	tz.setSpecialCharacters(";,:|={}/()");
	tz.openString(text);

	string token = tz.getToken();
	while (!tz.atEnd())
	{
		if (token == "{")
		{
			// Skip block
			while (!tz.atEnd() && token != "}")
				token = tz.getToken();
		}

		for (unsigned a = 0; a < block_names.size(); a++)
		{
			// Get jump block keyword
			string block = block_names[a];
			long skip = 0;
			if (block.Contains(":"))
			{
				wxArrayString sp = wxSplit(block, ':');
				sp.back().ToLong(&skip);
				block = sp[0];
			}

			if (S_CMPNOCASE(token, block))
			{
				string name = tz.getToken();
				for (int s = 0; s < skip; s++)
					name = tz.getToken();

				for (unsigned i = 0; i < ignore.size(); ++i)
					if (S_CMPNOCASE(name, ignore[i]))
						name = tz.getToken();

				// Numbered block, add block name
				if (name.IsNumber())
					name = S_FMT("%s %s", block, name);
				// Unnamed block, use block name
				if (name == "{" || name == ";")
					name = block;

				// Add jump point
				jump_points += S_FMT("%d,%s,", tz.lineNo() - 1, CHR(name));
			}
		}

		token = tz.getToken();
	}

	// Remove ending comma
	if (!jump_points.empty())
		jump_points.RemoveLast(1);

	// Send event
	wxThreadEvent* event = new wxThreadEvent(wxEVT_COMMAND_JTCALCULATOR_COMPLETED);
	event->SetString(jump_points);
	wxQueueEvent(handler, event);

	return nullptr;
}
示例#6
0
// -----------------------------------------------------------------------------
// 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();
	}
}