File: binaryexpressionparser.cpp

package info (click to toggle)
ufoai 2.5-4
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 82,128 kB
  • sloc: cpp: 225,227; python: 5,111; ansic: 4,133; php: 2,209; perl: 1,931; sh: 1,517; xml: 1,115; makefile: 401; sed: 11
file content (198 lines) | stat: -rw-r--r-- 4,909 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/**
 * @file
 */

/*
Copyright (C) 2002-2013 UFO: Alien Invasion.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "binaryexpressionparser.h"
#include "common.h"

typedef enum
{
	BEPERR_NONE, BEPERR_BRACE, BEPERR_NOEND, BEPERR_NOTFOUND
} binaryExpressionParserError_t;

/**
 * @brief Evaluates stuff like this expression <pre>(x & !y) ^ z</pre>
 */
class BinaryExpressionParser {
private:
	binaryExpressionParserError_t binaryExpressionParserError;
	BEPEvaluteCallback_t varFunc;
	char varName[MAX_VAR];
	bool result;
	const void* userdata;

	inline void SkipWhiteSpaces (const char** s) const
	{
		while (**s == ' ' || **s == '\t')
			(*s)++;
	}

	/**
	 * @brief Advance to the next char that is no whitespace
	 */
	inline void NextChar (const char** s) const
	{
		(*s)++;
		/* skip white-spaces too */
		SkipWhiteSpaces(s);
	}

	const char* GetSwitchName (const char** s)
	{
		int pos = 0;

		/* skip non printable chars and special chars that are used to define the binary expression */
		while (**s > ' ' && **s != '^' && **s != '|' && **s != '&' && **s != '!' && **s != '(' && **s != ')') {
			varName[pos++] = **s;
			(*s)++;
		}
		varName[pos] = '\0';

		return varName;
	}

	/**
	 * @brief Evaluates or and xor in the given string. This is the entry point, it delegates to the and checks
	 * that are done in @c CheckAnd
	 * @return The result of the evaluation
	 */
	bool CheckOR (const char** s)
	{
		bool result = false;
		enum {
			BEP_NONE, BEP_OR, BEP_EXCLUSIVE_OR
		};
		int goOn = BEP_NONE;

		SkipWhiteSpaces(s);
		do {
			if (goOn == BEP_EXCLUSIVE_OR)
				result ^= CheckAND(s);
			else
				result |= CheckAND(s);

			if (**s == '|') {
				goOn = BEP_OR;
				NextChar(s);
			} else if (**s == '^') {
				goOn = BEP_EXCLUSIVE_OR;
				NextChar(s);
			} else {
				goOn = BEP_NONE;
			}
		} while (goOn != BEP_NONE && !binaryExpressionParserError);

		return result;
	}

	bool CheckAND (const char** s)
	{
		bool result = true;
		bool negate = false;
		bool goOn = false;

		do {
			/* parse all negate chars and swap the flag accordingly */
			while (**s == '!') {
				negate ^= true;
				NextChar(s);
			}
			/* handling braces */
			if (**s == '(') {
				NextChar(s);
				/* and the result of the inner clause by calling the entry
				 * point again (and apply the negate flag) */
				result &= CheckOR(s) ^ negate;
				if (**s != ')')
					binaryExpressionParserError = BEPERR_BRACE;
				NextChar(s);
			} else {
				/* get the variable state by calling the evaluate callback */
				const int value = varFunc(GetSwitchName(s), userdata);
				if (value == -1)
					binaryExpressionParserError = BEPERR_NOTFOUND;
				else
					result &= value ^ negate;
				SkipWhiteSpaces(s);
			}

			/* check whether there is another and clause */
			if (**s == '&') {
				goOn = true;
				NextChar(s);
			} else {
				goOn = false;
			}
			negate = false;
		} while (goOn && !binaryExpressionParserError);

		return result;
	}

public:
	BinaryExpressionParser (const char* expr, BEPEvaluteCallback_t varFuncParam, const void* userdataPtr) :
		binaryExpressionParserError(BEPERR_NONE), varFunc(varFuncParam), userdata(userdataPtr)
	{
		const char* str = expr;
		result = CheckOR(&str);
		/* check for no end error */
		if (Q_strvalid(str) && !binaryExpressionParserError)
			binaryExpressionParserError = BEPERR_NOEND;
	}

	inline bool getResult() const
	{
		return result;
	}

	inline binaryExpressionParserError_t getError() const
	{
		return binaryExpressionParserError;
	}
};

bool BEP_Evaluate (const char* expr, BEPEvaluteCallback_t varFuncParam, const void* userdata)
{
	if (!Q_strvalid(expr))
		return true;

	BinaryExpressionParser bep(expr, varFuncParam, userdata);
	const bool result = bep.getResult();
	const binaryExpressionParserError_t error = bep.getError();

	switch (error) {
	case BEPERR_NONE:
		/* do nothing */
		return result;
	case BEPERR_BRACE:
		Com_Printf("')' expected in binary expression (%s).\n", expr);
		return true;
	case BEPERR_NOEND:
		Com_Printf("Unexpected end of condition in binary expression (%s).\n", expr);
		return result;
	case BEPERR_NOTFOUND:
		Com_Printf("Variable not found in binary expression (%s).\n", expr);
		return false;
	}
	Com_Error(ERR_FATAL, "Unknown CheckBEP error in binary expression (%s)", expr);
}