Clifford Wolf:

Another cleanup in expression handling



git-svn-id: http://svn.clifford.at/openscad/trunk@43 b57f626f-c46c-0410-a088-ec61d464b74c
stl_dim
clifford 2009-07-01 08:06:06 +00:00
parent b7ca4bfdb3
commit 27ecd0b1d0
5 changed files with 302 additions and 142 deletions

213
expr.cc
View File

@ -22,7 +22,6 @@
Expression::Expression()
{
type = 0;
const_value = NULL;
}
@ -36,124 +35,138 @@ Expression::~Expression()
Value Expression::evaluate(const Context *context) const
{
switch (type)
{
case '*':
if (type == "!")
return ! children[0]->evaluate(context);
if (type == "&&")
return children[0]->evaluate(context) && children[1]->evaluate(context);
if (type == "||")
return children[0]->evaluate(context) || children[1]->evaluate(context);
if (type == "*")
return children[0]->evaluate(context) * children[1]->evaluate(context);
case '/':
if (type == "/")
return children[0]->evaluate(context) / children[1]->evaluate(context);
case '%':
if (type == "%")
return children[0]->evaluate(context) % children[1]->evaluate(context);
case '+':
if (type == "+")
return children[0]->evaluate(context) + children[1]->evaluate(context);
case '-':
if (type == "-")
return children[0]->evaluate(context) - children[1]->evaluate(context);
case '?':
{
Value v = children[0]->evaluate(context);
if (v.type == Value::BOOL)
return children[v.b ? 1 : 2]->evaluate(context);
return Value();
}
case 'I':
return children[0]->evaluate(context).inv();
case 'C':
return *const_value;
case 'R':
{
Value v1 = children[0]->evaluate(context);
Value v2 = children[1]->evaluate(context);
Value v3 = children[2]->evaluate(context);
if (v1.type == Value::NUMBER && v2.type == Value::NUMBER && v3.type == Value::NUMBER) {
Value r = Value();
r.type = Value::RANGE;
r.range_begin = v1.num;
r.range_step = v2.num;
r.range_end = v3.num;
return r;
}
return Value();
}
case 'V':
{
Value v;
v.type = Value::VECTOR;
for (int i = 0; i < children.size(); i++)
v.vec.append(new Value(children[i]->evaluate(context)));
return v;
}
case 'L':
return context->lookup_variable(var_name);
case 'N':
{
Value v = children[0]->evaluate(context);
if (v.type == Value::VECTOR && var_name == QString("x"))
return *v.vec[0];
if (v.type == Value::VECTOR && var_name == QString("y"))
return *v.vec[1];
if (v.type == Value::VECTOR && var_name == QString("z"))
return *v.vec[2];
if (v.type == Value::RANGE && var_name == QString("begin"))
return Value(v.range_begin);
if (v.type == Value::RANGE && var_name == QString("step"))
return Value(v.range_step);
if (v.type == Value::RANGE && var_name == QString("end"))
return Value(v.range_end);
return Value();
}
case 'F':
{
QVector<Value> argvalues;
for (int i=0; i < children.size(); i++)
argvalues.append(children[i]->evaluate(context));
return context->evaluate_function(call_funcname, call_argnames, argvalues);
}
default:
abort();
if (type == "<")
return children[0]->evaluate(context) < children[1]->evaluate(context);
if (type == "<=")
return children[0]->evaluate(context) <= children[1]->evaluate(context);
if (type == "==")
return children[0]->evaluate(context) == children[1]->evaluate(context);
if (type == "!=")
return children[0]->evaluate(context) != children[1]->evaluate(context);
if (type == ">=")
return children[0]->evaluate(context) >= children[1]->evaluate(context);
if (type == ">")
return children[0]->evaluate(context) > children[1]->evaluate(context);
if (type == "?:") {
Value v = children[0]->evaluate(context);
if (v.type == Value::BOOL)
return children[v.b ? 1 : 2]->evaluate(context);
return Value();
}
if (type == "[]") {
Value v1 = children[0]->evaluate(context);
Value v2 = children[1]->evaluate(context);
if (v1.type == Value::VECTOR && v2.type == Value::NUMBER) {
int i = v2.num;
if (i < v1.vec.size())
return *v1.vec[i];
}
return Value();
}
if (type == "I")
return children[0]->evaluate(context).inv();
if (type == "C")
return *const_value;
if (type == "R") {
Value v1 = children[0]->evaluate(context);
Value v2 = children[1]->evaluate(context);
Value v3 = children[2]->evaluate(context);
if (v1.type == Value::NUMBER && v2.type == Value::NUMBER && v3.type == Value::NUMBER) {
Value r = Value();
r.type = Value::RANGE;
r.range_begin = v1.num;
r.range_step = v2.num;
r.range_end = v3.num;
return r;
}
return Value();
}
if (type == "V") {
Value v;
v.type = Value::VECTOR;
for (int i = 0; i < children.size(); i++)
v.vec.append(new Value(children[i]->evaluate(context)));
return v;
}
if (type == "L")
return context->lookup_variable(var_name);
if (type == "N")
{
Value v = children[0]->evaluate(context);
if (v.type == Value::VECTOR && var_name == QString("x"))
return *v.vec[0];
if (v.type == Value::VECTOR && var_name == QString("y"))
return *v.vec[1];
if (v.type == Value::VECTOR && var_name == QString("z"))
return *v.vec[2];
if (v.type == Value::RANGE && var_name == QString("begin"))
return Value(v.range_begin);
if (v.type == Value::RANGE && var_name == QString("step"))
return Value(v.range_step);
if (v.type == Value::RANGE && var_name == QString("end"))
return Value(v.range_end);
return Value();
}
if (type == "F") {
QVector<Value> argvalues;
for (int i=0; i < children.size(); i++)
argvalues.append(children[i]->evaluate(context));
return context->evaluate_function(call_funcname, call_argnames, argvalues);
}
abort();
}
QString Expression::dump() const
{
switch (type)
{
case '*':
case '/':
case '%':
case '+':
case '-':
if (type == "*" || type == "/" || type == "%" || type == "+" || type == "-" ||
type == "<" || type == "<=" || type == "==" || type == "!=" || type == ">=" || type == ">")
return QString("(%1 %2 %3)").arg(children[0]->dump(), QString(type), children[1]->dump());
case '?':
if (type == "?:")
return QString("(%1 ? %2 : %3)").arg(children[0]->dump(), children[1]->dump(), children[2]->dump());
case 'I':
if (type == "[]")
return QString("(%1[%2])").arg(children[0]->dump(), children[1]->dump());
if (type == "I")
return QString("(-%1)").arg(children[0]->dump());
case 'C':
if (type == "C")
return const_value->dump();
case 'R':
if (type == "R")
return QString("[%1 : %2 : %3]").arg(children[0]->dump(), children[1]->dump(), children[2]->dump());
case 'V':
if (type == "V")
return QString("[%1, %2, %3]").arg(children[0]->dump(), children[1]->dump(), children[2]->dump());
case 'L':
if (type == "L")
return var_name;
case 'N':
if (type == "N")
return QString("(%1.%2)").arg(children[0]->dump(), var_name);
case 'F':
{
QString text = call_funcname + QString("(");
for (int i=0; i < children.size(); i++) {
if (i > 0)
text += QString(", ");
if (!call_argnames[i].isEmpty())
text += call_argnames[i] + QString(" = ");
text += children[i]->dump();
}
return text + QString(")");
if (type == "F") {
QString text = call_funcname + QString("(");
for (int i=0; i < children.size(); i++) {
if (i > 0)
text += QString(", ");
if (!call_argnames[i].isEmpty())
text += call_argnames[i] + QString(" = ");
text += children[i]->dump();
}
default:
abort();
return text + QString(")");
}
abort();
}

27
lexer.l
View File

@ -55,29 +55,18 @@ extern const char *parser_input_buffer;
"$"?[a-zA-Z0-9_]+ { parserlval.text = strdup(yytext); return TOK_ID; }
\"[^"]*\" { parserlval.text = strdup(yytext); return TOK_STRING; }
"." return '.';
"," return ',';
";" return ';';
"?" return '?';
":" return ':';
"=" return '=';
"*" return '*';
"/" return '/';
"%" return '%';
"+" return '+';
"-" return '-';
"(" return '(';
")" return ')';
"{" return '{';
"}" return '}';
"[" return '[';
"]" return ']';
[\n\r\t ]
\/\/[^\n]*\n
"/*" BEGIN(comment);
<comment>"*/" BEGIN(INITIAL);
<comment>.|\n
. { fprintf(stderr, "Unrecognized input character in line %d: %s\n", lexerget_lineno(), yytext); exit(1); }
"<=" return LE;
">=" return GE;
"==" return EQ;
"!=" return NE;
"&&" return AND;
"||" return OR;
. { return yytext[0]; }

View File

@ -104,11 +104,23 @@ public:
Value(const Value &v);
Value& operator = (const Value &v);
Value operator ! () const;
Value operator && (const Value &v) const;
Value operator || (const Value &v) const;
Value operator + (const Value &v) const;
Value operator - (const Value &v) const;
Value operator * (const Value &v) const;
Value operator / (const Value &v) const;
Value operator % (const Value &v) const;
Value operator < (const Value &v) const;
Value operator <= (const Value &v) const;
Value operator == (const Value &v) const;
Value operator != (const Value &v) const;
Value operator >= (const Value &v) const;
Value operator > (const Value &v) const;
Value inv() const;
bool getnum(double &v) const;
@ -131,8 +143,11 @@ public:
QString call_funcname;
QVector<QString> call_argnames;
// Math operators: * / % + -
// Condition (?: operator): ?
// Boolean: ! && ||
// Operators: * / % + -
// Relations: < <= == != >= >
// Vector element: []
// Condition operator: ?:
// Invert (prefix '-'): I
// Constant value: C
// Create Range: R
@ -141,7 +156,7 @@ public:
// Lookup Variable: L
// Lookup member per name: N
// Function call: F
char type;
QString type;
Expression();
~Expression();

105
parser.y
View File

@ -66,9 +66,15 @@ public:
%token TOK_FALSE
%token TOK_UNDEF
%token LE GE EQ NE AND OR
%left '+' '-'
%left '*' '/' '%'
%left '.'
%left '<' LE GE '>'
%left EQ NE
%left AND
%left OR
%type <expr> expr
%type <value> vector_const
@ -173,69 +179,69 @@ single_module_instantciation:
expr:
TOK_TRUE {
$$ = new Expression();
$$->type = 'C';
$$->type = "C";
$$->const_value = new Value(true);
} |
TOK_FALSE {
$$ = new Expression();
$$->type = 'C';
$$->type = "C";
$$->const_value = new Value(false);
} |
TOK_UNDEF {
$$ = new Expression();
$$->type = 'C';
$$->type = "C";
$$->const_value = new Value();
} |
TOK_ID {
$$ = new Expression();
$$->type = 'L';
$$->type = "L";
$$->var_name = QString($1);
free($1);
} |
expr '.' TOK_ID {
$$ = new Expression();
$$->type = 'N';
$$->type = "N";
$$->children.append($1);
$$->var_name = QString($3);
free($3);
} |
TOK_STRING {
$$ = new Expression();
$$->type = 'C';
$$->type = "C";
$$->const_value = new Value(QString($1));
free($1);
} |
TOK_NUMBER {
$$ = new Expression();
$$->type = 'C';
$$->type = "C";
$$->const_value = new Value($1);
} |
'[' expr ':' expr ']' {
Expression *e_one = new Expression();
e_one->type = 'C';
e_one->type = "C";
e_one->const_value = new Value(1.0);
$$ = new Expression();
$$->type = 'R';
$$->type = "R";
$$->children.append($2);
$$->children.append(e_one);
$$->children.append($4);
} |
'[' expr ':' expr ':' expr ']' {
$$ = new Expression();
$$->type = 'R';
$$->type = "R";
$$->children.append($2);
$$->children.append($4);
$$->children.append($6);
} |
'[' ']' {
$$ = new Expression();
$$->type = 'C';
$$->type = "C";
$$->const_value = new Value();
$$->const_value->type = Value::VECTOR;
} |
'[' vector_const ']' {
$$ = new Expression();
$$->type = 'C';
$$->type = "C";
$$->const_value = $2;
} |
'[' vector_expr ']' {
@ -243,31 +249,79 @@ expr:
} |
expr '*' expr {
$$ = new Expression();
$$->type = '*';
$$->type = "*";
$$->children.append($1);
$$->children.append($3);
} |
expr '/' expr {
$$ = new Expression();
$$->type = '/';
$$->type = "/";
$$->children.append($1);
$$->children.append($3);
} |
expr '%' expr {
$$ = new Expression();
$$->type = '%';
$$->type = "%";
$$->children.append($1);
$$->children.append($3);
} |
expr '+' expr {
$$ = new Expression();
$$->type = '+';
$$->type = "+";
$$->children.append($1);
$$->children.append($3);
} |
expr '-' expr {
$$ = new Expression();
$$->type = '-';
$$->type = "-";
$$->children.append($1);
$$->children.append($3);
} |
expr '<' expr {
$$ = new Expression();
$$->type = "<";
$$->children.append($1);
$$->children.append($3);
} |
expr LE expr {
$$ = new Expression();
$$->type = "<=";
$$->children.append($1);
$$->children.append($3);
} |
expr EQ expr {
$$ = new Expression();
$$->type = "==";
$$->children.append($1);
$$->children.append($3);
} |
expr NE expr {
$$ = new Expression();
$$->type = "!=";
$$->children.append($1);
$$->children.append($3);
} |
expr GE expr {
$$ = new Expression();
$$->type = ">=";
$$->children.append($1);
$$->children.append($3);
} |
expr '>' expr {
$$ = new Expression();
$$->type = "<";
$$->children.append($1);
$$->children.append($3);
} |
expr AND expr {
$$ = new Expression();
$$->type = "&&";
$$->children.append($1);
$$->children.append($3);
} |
expr OR expr {
$$ = new Expression();
$$->type = "||";
$$->children.append($1);
$$->children.append($3);
} |
@ -276,7 +330,12 @@ expr:
} |
'-' expr {
$$ = new Expression();
$$->type = 'I';
$$->type = "I";
$$->children.append($2);
} |
'!' expr {
$$ = new Expression();
$$->type = "!";
$$->children.append($2);
} |
'(' expr ')' {
@ -284,14 +343,20 @@ expr:
} |
expr '?' expr ':' expr {
$$ = new Expression();
$$->type = '?';
$$->type = "?:";
$$->children.append($1);
$$->children.append($3);
$$->children.append($5);
} |
expr '[' expr ']' {
$$ = new Expression();
$$->type = "[]";
$$->children.append($1);
$$->children.append($3);
} |
TOK_ID '(' arguments_call ')' {
$$ = new Expression();
$$->type = 'F';
$$->type = "F";
$$->call_funcname = QString($1);
$$->call_argnames = $3->argnames;
$$->children = $3->argexpr;

View File

@ -73,6 +73,30 @@ Value& Value::operator = (const Value &v)
return *this;
}
Value Value::operator ! () const
{
if (type == BOOL) {
return Value(!b);
}
return Value();
}
Value Value::operator && (const Value &v) const
{
if (type == BOOL && v.type == BOOL) {
return Value(b && v.b);
}
return Value();
}
Value Value::operator || (const Value &v) const
{
if (type == BOOL && v.type == BOOL) {
return Value(b || v.b);
}
return Value();
}
Value Value::operator + (const Value &v) const
{
if (type == VECTOR && v.type == VECTOR) {
@ -155,6 +179,60 @@ Value Value::operator % (const Value &v) const
return Value();
}
Value Value::operator < (const Value &v) const
{
if (type == NUMBER && v.type == NUMBER) {
return Value(num < v.num);
}
return Value();
}
Value Value::operator <= (const Value &v) const
{
if (type == NUMBER && v.type == NUMBER) {
return Value(num <= v.num);
}
return Value();
}
Value Value::operator == (const Value &v) const
{
if (type == BOOL && v.type == BOOL) {
return Value(b == v.b);
}
if (type == NUMBER && v.type == NUMBER) {
return Value(num == v.num);
}
return Value();
}
Value Value::operator != (const Value &v) const
{
if (type == BOOL && v.type == BOOL) {
return Value(b != v.b);
}
if (type == NUMBER && v.type == NUMBER) {
return Value(num != v.num);
}
return Value();
}
Value Value::operator >= (const Value &v) const
{
if (type == NUMBER && v.type == NUMBER) {
return Value(num >= v.num);
}
return Value();
}
Value Value::operator > (const Value &v) const
{
if (type == NUMBER && v.type == NUMBER) {
return Value(num > v.num);
}
return Value();
}
Value Value::inv() const
{
if (type == VECTOR) {