コード例 #1
0
ファイル: ui_actions.cpp プロジェクト: MyWifeRules/ufoai-1
/**
 * @brief Allocate and initialize a command action
 * @param[in] command A command for the action
 * @return An initialised action
 */
uiAction_t* UI_AllocStaticCommandAction (const char *command)
{
	uiAction_t* action = UI_AllocStaticAction();
	action->type = EA_CMD;
	action->d.terminal.d1.constString = command;
	return action;
}
コード例 #2
0
ファイル: ui_parse.cpp プロジェクト: ArkyRomania/ufoai
/**
 * @brief Parse actions and return action list
 * @return The first element from a list of action
 * @sa ea_t
 * @todo need cleanup, compute action out of the final memory; reduce number of var
 */
static uiAction_t* UI_ParseActionList (uiNode_t* node, const char** text, const char** token)
{
	const char* errhead = "UI_ParseActionList: unexpected end of file (in event)";
	uiAction_t* firstAction;
	uiAction_t* lastAction;
	uiAction_t* action;

	lastAction = nullptr;
	firstAction = nullptr;

	/* prevent bad position */
	if ((*token)[0] != '{') {
		Com_Printf("UI_ParseActionList: token \"{\" expected, but \"%s\" found (in event) (node: %s)\n", *token, UI_GetPath(node));
		return nullptr;
	}

	while (true) {
		bool result;
		int type = EA_NULL;

		/* get new token */
		*token = Com_EParse(text, errhead, nullptr);
		if (!*token)
			return nullptr;

		if ((*token)[0] == '}')
			break;

		type = UI_GetActionTokenType(*token, EA_ACTION);
		/* setter form */
		if (type == EA_NULL && (*token)[0] == '*')
			type = EA_ASSIGN;

		/* unknown, we break the parsing */
		if (type == EA_NULL) {
			Com_Printf("UI_ParseActionList: unknown token \"%s\" ignored (in event) (node: %s)\n", *token, UI_GetPath(node));
			return nullptr;
		}

		/* add the action */
		action = UI_AllocStaticAction();
		/** @todo better to append the action after initialization */
		if (lastAction)
			lastAction->next = action;
		if (!firstAction)
			firstAction = action;
		action->type = type;

		/* decode action */
		switch (action->type) {
		case EA_CMD:
			/* get parameter values */
			*token = Com_EParse(text, errhead, nullptr);
			if (!*text)
				return nullptr;

			/* get the value */
			action->d.terminal.d1.constString = UI_AllocStaticString(*token, 0);
			break;

		case EA_ASSIGN:
			result = UI_ParseSetAction(node, action, text, token, errhead);
			if (!result)
				return nullptr;
			break;

		case EA_CALL:
			result = UI_ParseCallAction(node, action, text, token, errhead);
			if (!result)
				return nullptr;
			break;

		case EA_DELETE:
			{
				uiAction_t* expression;
				expression = UI_ParseExpression(text);
				if (expression == nullptr)
					return nullptr;

				if (expression->type != EA_VALUE_CVARNAME) {
					Com_Printf("UI_ParseActionList: \"delete\" keyword only support cvarname (node: %s)\n", UI_GetPath(node));
					return nullptr;
				}

				action->d.nonTerminal.left = expression;
				break;
			}

		case EA_ELIF:
			/* check previous action */
			if (!lastAction || (lastAction->type != EA_IF && lastAction->type != EA_ELIF)) {
				Com_Printf("UI_ParseActionList: 'elif' must be set after an 'if' or an 'elif' (node: %s)\n", UI_GetPath(node));
				return nullptr;
			}
			/* then it execute EA_IF, no break */
		case EA_WHILE:
		case EA_IF:
			{
				uiAction_t* expression;

				/* get the condition */
				expression = UI_ParseExpression(text);
				if (expression == nullptr)
					return nullptr;
				action->d.nonTerminal.left = expression;

				/* get the action block */
				*token = Com_EParse(text, errhead, nullptr);
				if (!*text)
					return nullptr;
				action->d.nonTerminal.right = UI_ParseActionList(node, text, token);
				if (action->d.nonTerminal.right == nullptr) {
					switch (action->type) {
					case EA_IF:
						Com_Printf("UI_ParseActionList: block expected after \"if\" (node: %s)\n", UI_GetPath(node));
						break;
					case EA_ELIF:
						Com_Printf("UI_ParseActionList: block expected after \"elif\" (node: %s)\n", UI_GetPath(node));
						break;
					case EA_WHILE:
						Com_Printf("UI_ParseActionList: block expected after \"while\" (node: %s)\n", UI_GetPath(node));
						break;
					default:
						Com_Printf("UI_ParseActionList: cannot determine statement type (node: %s)\n", UI_GetPath(node));
					}
					return nullptr;
				}
				break;
			}

		case EA_FORCHILDIN:
			{
				uiAction_t* expression;

				/* get the node */
				expression = UI_ParseExpression(text);
				if (expression == nullptr) {
					return nullptr;
				}
				action->d.nonTerminal.left = expression;

				/* check the type */
				type = action->d.nonTerminal.left->type;
				if (type != EA_VALUE_PATHNODE && type != EA_VALUE_PATHNODE_WITHINJECTION) {
					Com_Printf("UI_ParseActionList: Node property expected. Type '%x' found\n", type);
					return nullptr;
				}

				/* get the action block */
				*token = Com_EParse(text, errhead, nullptr);
				if (!*text)
					return nullptr;
				action->d.nonTerminal.right = UI_ParseActionList(node, text, token);
				if (action->d.nonTerminal.right == nullptr) {
					Com_Printf("UI_ParseActionList: block expected after \"forchildin\" (node: %s)\n", UI_GetPath(node));
					return nullptr;
				}
				break;
			}

		case EA_ELSE:
			/* check previous action */
			if (!lastAction || (lastAction->type != EA_IF && lastAction->type != EA_ELIF)) {
				Com_Printf("UI_ParseActionList: 'else' must be set after an 'if' or an 'elif' (node: %s)\n", UI_GetPath(node));
				return nullptr;
			}

			/* get the action block */
			*token = Com_EParse(text, errhead, nullptr);
			if (!*text)
				return nullptr;
			action->d.nonTerminal.left = nullptr;
			action->d.nonTerminal.right = UI_ParseActionList(node, text, token);
			if (action->d.nonTerminal.right == nullptr) {
				Com_Printf("UI_ParseActionList: block expected after \"else\" (node: %s)\n", UI_GetPath(node));
				return nullptr;
			}
			break;

		default:
			assert(false);
		}

		/* step */
		lastAction = action;
	}

	assert((*token)[0] == '}');

	/* return non nullptr value */
	if (firstAction == nullptr) {
		firstAction = UI_AllocStaticAction();
	}

	return firstAction;
}
コード例 #3
0
ファイル: ui_parse.cpp プロジェクト: ArkyRomania/ufoai
/**
 * @brief Parser for setter command
 */
static bool UI_ParseSetAction (uiNode_t* node, uiAction_t* action, const char** text, const char** token, const char* errhead)
{
	const value_t* property;
	int type;
	uiAction_t* localAction;

	assert((*token)[0] == '*');

	Com_UnParseLastToken();
	action->d.nonTerminal.left = UI_ParseExpression(text);

	type = action->d.nonTerminal.left->type;
	if (type != EA_VALUE_CVARNAME && type != EA_VALUE_CVARNAME_WITHINJECTION
		&& type != EA_VALUE_PATHPROPERTY && type != EA_VALUE_PATHPROPERTY_WITHINJECTION) {
		Com_Printf("UI_ParseSetAction: Cvar or Node property expected. Type '%i' found\n", type);
		return false;
	}

	/* must use "equal" char between name and value */
	*token = Com_EParse(text, errhead, nullptr);
	if (!*text)
		return false;
	if (!Q_streq(*token, "=")) {
		Com_Printf("UI_ParseSetAction: Assign sign '=' expected between variable and value. '%s' found in node %s.\n", *token, UI_GetPath(node));
		return false;
	}

	/* get the value */
	if (type == EA_VALUE_CVARNAME || type == EA_VALUE_CVARNAME_WITHINJECTION) {
		action->d.nonTerminal.right = UI_ParseExpression(text);
		return true;
	}

	property = (const value_t*) action->d.nonTerminal.left->d.terminal.d2.data;

	*token = Com_EParse(text, errhead, nullptr);
	if (!*text)
		return false;

	if (Q_streq(*token, "{")) {
		uiAction_t* actionList;

		if (property != nullptr && property->type != V_UI_ACTION) {
			Com_Printf("UI_ParseSetAction: Property %s@%s do not expect code block.\n", UI_GetPath(node), property->string);
			return false;
		}

		actionList = UI_ParseActionList(node, text, token);
		if (actionList == nullptr)
			return false;

		localAction = UI_AllocStaticAction();
		localAction->type = EA_VALUE_RAW;
		localAction->d.terminal.d1.data = actionList;
		localAction->d.terminal.d2.integer = V_UI_ACTION;
		action->d.nonTerminal.right = localAction;

		return true;
	}

	if (Q_streq(*token, "(")) {
		Com_UnParseLastToken();
		action->d.nonTerminal.right = UI_ParseExpression(text);
		return true;
	}

	/* @todo everything should come from UI_ParseExpression */

	if (UI_IsInjectedString(*token)) {
		localAction = UI_AllocStaticAction();
		localAction->type = EA_VALUE_STRING_WITHINJECTION;
		localAction->d.terminal.d1.data = UI_AllocStaticString(*token, 0);
		action->d.nonTerminal.right = localAction;
		return true;
	}

	localAction = UI_AllocStaticAction();
	UI_InitRawActionValue(localAction, node, property, *token);
	action->d.nonTerminal.right = localAction;
	return true;
}
コード例 #4
0
ファイル: ui_expression.cpp プロジェクト: radius75/ufoai
uiAction_t *UI_ParseExpression (const char **text)
{
	const char* token;

	token = Com_Parse(text);
	if (*text == nullptr)
		return nullptr;

	if (Q_streq(token, "(")) {
		uiAction_t *expression;
		uiAction_t *e;

		e = UI_ParseExpression(text);

		token = Com_Parse(text);
		if (*text == nullptr)
			return nullptr;

		/* unary operator or unneed "( ... )" */
		if (Q_streq(token, ")"))
			return e;

		/* then its an operator */
		expression = UI_AllocStaticAction();
		expression->d.nonTerminal.left = e;
		expression->type = UI_GetActionTokenType(token, EA_BINARYOPERATOR);
		if (expression->type == EA_nullptr) {
			Com_Printf("UI_ParseExpression: Invalid 'expression' statement. Unknown '%s' operator\n", token);
			return nullptr;
		}

		e = UI_ParseExpression(text);
		expression->d.nonTerminal.right = e;

		token = Com_Parse(text);
		if (*text == nullptr)
			return nullptr;
		if (!Q_streq(token, ")")) {
			Com_Printf("UI_ParseExpression: Token ')' expected\n");
			return nullptr;
		}

		return expression;
	} else {
		const int type = UI_GetActionTokenType(token, EA_UNARYOPERATOR);
		if (type == EA_nullptr) {
			Com_UnParseLastToken();
			return UI_ParseValueExpression(text);
		} else {
			uiAction_t *expression = UI_AllocStaticAction();
			uiAction_t *e;

			e = UI_ParseExpression(text);
			expression->type = type;
			expression->d.nonTerminal.left = e;

			if (expression->type == EA_OPERATOR_EXISTS) {
				switch (e->type) {
				case EA_VALUE_CVARNAME:
				case EA_VALUE_CVARNAME_WITHINJECTION:
				case EA_VALUE_PATHNODE:
				case EA_VALUE_PATHNODE_WITHINJECTION:
					break;
				default:
					Com_Printf("UI_ParseExpression: Cvar or Node path expected, but type %d found\n", e->type);
					return nullptr;
				}
			}
			return expression;
		}
	}
}
コード例 #5
0
ファイル: ui_expression.cpp プロジェクト: radius75/ufoai
/**
 * @brief Read a value from the stream and init an action with it
 * @return An initialized action else nullptr
 */
static uiAction_t *UI_ParseValueExpression (const char **text)
{
	const char* token;
	uiAction_t *expression = UI_AllocStaticAction();

	token = Com_Parse(text);
	if (*text == nullptr) {
		Com_Printf("UI_ParseTerminalExpression: Token expected\n");
		return nullptr;
	}

	/* it is a const string (or an injection tag for compatibility) */
	if (Com_GetType(text) == TT_QUOTED_WORD || token[0] == '<') {
		expression->d.terminal.d1.constString = UI_AllocStaticString(token, 0);
		if (UI_IsInjectedString(token))
			expression->type = EA_VALUE_STRING_WITHINJECTION;
		else
			expression->type = EA_VALUE_STRING;
		return expression;
	}

	/* it is a param */
	if (!Q_strncasecmp(token, "param", 5)) {
		if (!Q_strcasecmp(token, "paramcount")) {
			expression->type = EA_VALUE_PARAMCOUNT;
			return expression;
		} else if (token[5] >= '1' && token[5] <= '9') {
			int i;
			if (sscanf(token + 5, "%i", &i) == 1) {
				/* token range 1-9 already avoid 0 */
				assert(i != 0);
				/** @todo when it is possible, we must check range of param id */
				expression->type = EA_VALUE_PARAM;
				expression->d.terminal.d1.integer = i;
				return expression;
			}
		}
	}

	/* it is a cvarname */
	if (char const* const cvarName = Q_strstart(token, "*cvar:")) {
		expression->d.terminal.d1.constString = UI_AllocStaticString(cvarName, 0);
		if (UI_IsInjectedString(cvarName))
			expression->type = EA_VALUE_CVARNAME_WITHINJECTION;
		else
			expression->type = EA_VALUE_CVARNAME;
		return expression;
	}

	/* it is a node property or it is a OLD syntax node property */
	/** @todo We MUST remove the OLD code as fast as possible */
	if (char const* path = Q_strstart(token, "*")) {
		const char *propertyName;
#if 0	/* it looks useless, an unused cache */
		const value_t *property;
#endif

		char const* const relativeToNode = Q_strstart(path, "node:");
		if (relativeToNode)
			path = relativeToNode;

		if (UI_IsInjectedString(path))
			expression->type = EA_VALUE_PATHPROPERTY_WITHINJECTION;
		else
			expression->type = EA_VALUE_PATHPROPERTY;
		if (!relativeToNode) {
			Com_Printf("UI_ParseExpression: Old syntax, please prefix '%s' with \"*node:root.\" \n", token);
			path = va("root.%s", path);
		}
		expression->d.terminal.d1.constString = UI_AllocStaticString(path, 0);

		/* get property name */
		propertyName = strchr(path, '@');
		if (propertyName == nullptr) {
			if (expression->type == EA_VALUE_PATHPROPERTY_WITHINJECTION)
				expression->type = EA_VALUE_PATHNODE_WITHINJECTION;
			else
				expression->type = EA_VALUE_PATHNODE;
			return expression;
		}
		propertyName++;

		return expression;
	}

	/* unsigned and signed number */
	if ((token[0] >= '0' && token[0] <= '9')
		|| (token[0] == '-' && token[1] >= '0' && token[1] <= '9')) {
		/** @todo use a better check - e.g. Com_ParseValue with V_INT or V_FLOAT */
		float f = atof(token);
		expression->d.terminal.d1.number = f;
		expression->type = EA_VALUE_FLOAT;
		return expression;
	}

	/* boolean */
	if (Q_streq(token, "true")) {
		expression->d.terminal.d1.number = 1.0;
		expression->type = EA_VALUE_FLOAT;
		return expression;
	}
	if (Q_streq(token, "false")) {
		expression->d.terminal.d1.number = 0.0;
		expression->type = EA_VALUE_FLOAT;
		return expression;
	}

	Com_Error(ERR_FATAL, "UI_ParseValueExpression: Token \"%s\" unknown. String must use quotes, cvar and nodes must use prefix.\n", token);
}