Hook libeval compiler up to rule parser
- convert expression string tokens to single-quote-delimited - fix bug where netclass assignments weren't getting updated after board setup dialog - move property manager rebuild to lazy evaluation - improve performance with wider use of const& - retire DRC_SELECTOR stuff - use wxString for GUI stuff (particularly translated stuff) - fix EqualTo() to return false instead of asserting when op types don't match - fix buffer overruns with fixed-size string buffers - make expression function calls case-insensitive - integrate expression errors into rule parser - produce more and better error messages - keep BOARD_ITEM ptrs const as long as possible - fix a couple of uninitialized variables
This commit is contained in:
parent
6d8fb94d86
commit
095937563b
|
@ -971,114 +971,114 @@ static YYACTIONTYPE yy_reduce(
|
|||
break;
|
||||
case 1: /* expr ::= G_VALUE */
|
||||
#line 58 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_NUMBER; yylhsminor.yy0.value = yymsp[0].minor.yy0.value; yylhsminor.yy0.leaf[0] = yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; }
|
||||
{ yylhsminor.yy0.op = TR_NUMBER; yylhsminor.yy0.value = yymsp[0].minor.yy0.value; yylhsminor.yy0.leaf[0] = yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 976 "grammar.c"
|
||||
yymsp[0].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 2: /* expr ::= G_VALUE G_UNIT */
|
||||
#line 59 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_NUMBER; yylhsminor.yy0.value = yymsp[-1].minor.yy0.value; yylhsminor.yy0.leaf[0] = newNode( TR_UNIT, yymsp[0].minor.yy0.value.type, ""); yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; }
|
||||
{ yylhsminor.yy0.op = TR_NUMBER; yylhsminor.yy0.value = yymsp[-1].minor.yy0.value; yylhsminor.yy0.leaf[0] = newNode( TR_UNIT, yymsp[0].minor.yy0.value.type, ""); yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 982 "grammar.c"
|
||||
yymsp[-1].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 3: /* expr ::= G_STRING */
|
||||
#line 60 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_STRING; yylhsminor.yy0.value = yymsp[0].minor.yy0.value; yylhsminor.yy0.leaf[0] = yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; }
|
||||
{ yylhsminor.yy0.op = TR_STRING; yylhsminor.yy0.value = yymsp[0].minor.yy0.value; yylhsminor.yy0.leaf[0] = yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 988 "grammar.c"
|
||||
yymsp[0].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 4: /* expr ::= G_IDENTIFIER */
|
||||
#line 61 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_IDENTIFIER; yylhsminor.yy0.value = yymsp[0].minor.yy0.value; yylhsminor.yy0.leaf[0] = yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; }
|
||||
{ yylhsminor.yy0.op = TR_IDENTIFIER; yylhsminor.yy0.value = yymsp[0].minor.yy0.value; yylhsminor.yy0.leaf[0] = yylhsminor.yy0.leaf[1] = NULL; yylhsminor.yy0.valid = true; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 994 "grammar.c"
|
||||
yymsp[0].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 5: /* expr ::= expr G_LESS_THAN expr */
|
||||
#line 62 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_LESS; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_OP_LESS; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1000 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 6: /* expr ::= expr G_GREATER_THAN expr */
|
||||
#line 63 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_GREATER; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_OP_GREATER; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1006 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 7: /* expr ::= expr G_LESS_EQUAL_THAN expr */
|
||||
#line 64 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_LESS_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_OP_LESS_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1012 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 8: /* expr ::= expr G_GREATER_EQUAL_THAN expr */
|
||||
#line 65 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_GREATER_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_OP_GREATER_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1018 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 9: /* expr ::= expr G_NOT_EQUAL expr */
|
||||
#line 66 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_NOT_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_OP_NOT_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1024 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 10: /* expr ::= expr G_BOOL_AND expr */
|
||||
#line 67 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_BOOL_AND; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_OP_BOOL_AND; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1030 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 11: /* expr ::= expr G_BOOL_OR expr */
|
||||
#line 68 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_BOOL_OR; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_OP_BOOL_OR; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1036 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 12: /* expr ::= expr G_PLUS expr */
|
||||
#line 69 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_ADD; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_OP_ADD; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1042 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 13: /* expr ::= expr G_MINUS expr */
|
||||
#line 70 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_SUB; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_OP_SUB; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1048 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 14: /* expr ::= expr G_MULT expr */
|
||||
#line 71 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_MUL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_OP_MUL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1054 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 15: /* expr ::= expr G_DIVIDE expr */
|
||||
#line 72 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_DIV; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_OP_DIV; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1060 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 16: /* expr ::= expr G_EQUAL expr */
|
||||
#line 73 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_OP_EQUAL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1066 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 17: /* expr ::= expr G_STRUCT_REF expr */
|
||||
#line 75 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_STRUCT_REF; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; }
|
||||
{ yylhsminor.yy0.op = TR_STRUCT_REF; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-2].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[0].minor.yy0); yylhsminor.yy0.valid=yymsp[-2].minor.yy0.valid && yymsp[0].minor.yy0.valid; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1072 "grammar.c"
|
||||
yymsp[-2].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
case 18: /* expr ::= G_PARENL expr G_PARENR */
|
||||
#line 77 "grammar.lemon"
|
||||
{ yymsp[-2].minor.yy0.op = yymsp[-1].minor.yy0.op; yymsp[-2].minor.yy0.value = yymsp[-1].minor.yy0.value; yymsp[-2].minor.yy0.valid=yymsp[-1].minor.yy0.valid; yymsp[-2].minor.yy0.leaf[0] = yymsp[-1].minor.yy0.leaf[0]; yymsp[-2].minor.yy0.leaf[1] = yymsp[-1].minor.yy0.leaf[1]; }
|
||||
{ yymsp[-2].minor.yy0.op = yymsp[-1].minor.yy0.op; yymsp[-2].minor.yy0.value = yymsp[-1].minor.yy0.value; yymsp[-2].minor.yy0.valid=yymsp[-1].minor.yy0.valid; yymsp[-2].minor.yy0.leaf[0] = yymsp[-1].minor.yy0.leaf[0]; yymsp[-2].minor.yy0.leaf[1] = yymsp[-1].minor.yy0.leaf[1]; yymsp[-2].minor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1078 "grammar.c"
|
||||
break;
|
||||
case 19: /* expr ::= G_IDENTIFIER G_PARENL expr G_PARENR */
|
||||
#line 78 "grammar.lemon"
|
||||
{ yylhsminor.yy0.op = TR_OP_FUNC_CALL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-3].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[-1].minor.yy0); yylhsminor.yy0.valid=1; }
|
||||
{ yylhsminor.yy0.op = TR_OP_FUNC_CALL; yylhsminor.yy0.leaf[0] = copyNode(yymsp[-3].minor.yy0); yylhsminor.yy0.leaf[1] = copyNode(yymsp[-1].minor.yy0); yylhsminor.yy0.valid=1; yylhsminor.yy0.srcPos = pEval->GetSourcePos(); }
|
||||
#line 1083 "grammar.c"
|
||||
yymsp[-3].minor.yy0 = yylhsminor.yy0;
|
||||
break;
|
||||
|
|
|
@ -53,27 +53,27 @@ in ::= in stmt.
|
|||
|
||||
/* A statement can be empty, an expr or an expr followed by ';' */
|
||||
stmt ::= G_ENDS.
|
||||
stmt ::= expr(A) G_ENDS. { pEval->setRoot(A); }
|
||||
//stmt ::= expr G_SEMCOL. { pEval->setRoot(NULL) }
|
||||
stmt ::= expr(A) G_ENDS. { pEval->setRoot(A); }
|
||||
//stmt ::= expr G_SEMCOL. { pEval->setRoot(NULL); }
|
||||
|
||||
expr(A) ::= G_VALUE(B). { A.op = TR_NUMBER; A.value = B.value; A.leaf[0] = A.leaf[1] = NULL; A.valid = true; }
|
||||
expr(A) ::= G_VALUE(B) G_UNIT(C). { A.op = TR_NUMBER; A.value = B.value; A.leaf[0] = newNode( TR_UNIT, C.value.type, ""); A.leaf[1] = NULL; A.valid = true; }
|
||||
expr(A) ::= G_STRING(B). { A.op = TR_STRING; A.value = B.value; A.leaf[0] = A.leaf[1] = NULL; A.valid = true; }
|
||||
expr(A) ::= G_IDENTIFIER(B). { A.op = TR_IDENTIFIER; A.value = B.value; A.leaf[0] = A.leaf[1] = NULL; A.valid = true; }
|
||||
expr(A) ::= expr(B) G_LESS_THAN expr(C). { A.op = TR_OP_LESS; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= expr(B) G_GREATER_THAN expr(C). { A.op = TR_OP_GREATER; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= expr(B) G_LESS_EQUAL_THAN expr(C). { A.op = TR_OP_LESS_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= expr(B) G_GREATER_EQUAL_THAN expr(C). { A.op = TR_OP_GREATER_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= expr(B) G_NOT_EQUAL expr(C). { A.op = TR_OP_NOT_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= expr(B) G_BOOL_AND expr(C). { A.op = TR_OP_BOOL_AND; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= expr(B) G_BOOL_OR expr(C). { A.op = TR_OP_BOOL_OR; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= expr(B) G_PLUS expr(C). { A.op = TR_OP_ADD; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= expr(B) G_MINUS expr(C). { A.op = TR_OP_SUB; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= expr(B) G_MULT expr(C). { A.op = TR_OP_MUL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= expr(B) G_DIVIDE expr(C). { A.op = TR_OP_DIV; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= expr(B) G_EQUAL expr(C). { A.op = TR_OP_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= G_VALUE(B). { A.op = TR_NUMBER; A.value = B.value; A.leaf[0] = A.leaf[1] = NULL; A.valid = true; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= G_VALUE(B) G_UNIT(C). { A.op = TR_NUMBER; A.value = B.value; A.leaf[0] = newNode(TR_UNIT, C.value.type, ""); A.leaf[1] = NULL; A.valid = true; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= G_STRING(B). { A.op = TR_STRING; A.value = B.value; A.leaf[0] = A.leaf[1] = NULL; A.valid = true; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= G_IDENTIFIER(B). { A.op = TR_IDENTIFIER; A.value = B.value; A.leaf[0] = A.leaf[1] = NULL; A.valid = true; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= expr(B) G_LESS_THAN expr(C). { A.op = TR_OP_LESS; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= expr(B) G_GREATER_THAN expr(C). { A.op = TR_OP_GREATER; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= expr(B) G_LESS_EQUAL_THAN expr(C). { A.op = TR_OP_LESS_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= expr(B) G_GREATER_EQUAL_THAN expr(C). { A.op = TR_OP_GREATER_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= expr(B) G_NOT_EQUAL expr(C). { A.op = TR_OP_NOT_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= expr(B) G_BOOL_AND expr(C). { A.op = TR_OP_BOOL_AND; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= expr(B) G_BOOL_OR expr(C). { A.op = TR_OP_BOOL_OR; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= expr(B) G_PLUS expr(C). { A.op = TR_OP_ADD; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= expr(B) G_MINUS expr(C). { A.op = TR_OP_SUB; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= expr(B) G_MULT expr(C). { A.op = TR_OP_MUL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= expr(B) G_DIVIDE expr(C). { A.op = TR_OP_DIV; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= expr(B) G_EQUAL expr(C). { A.op = TR_OP_EQUAL; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid = B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
|
||||
expr(A) ::= expr(B) G_STRUCT_REF expr(C). { A.op = TR_STRUCT_REF; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; }
|
||||
expr(A) ::= expr(B) G_STRUCT_REF expr(C). { A.op = TR_STRUCT_REF; A.leaf[0] = copyNode(B); A.leaf[1] = copyNode(C); A.valid=B.valid && C.valid; A.srcPos = pEval->GetSourcePos(); }
|
||||
|
||||
expr(A) ::= G_PARENL expr(B) G_PARENR. { A.op = B.op; A.value = B.value; A.valid=B.valid; A.leaf[0] = B.leaf[0]; A.leaf[1] = B.leaf[1]; }
|
||||
expr(A) ::= G_IDENTIFIER(func_name) G_PARENL expr(B) G_PARENR. { A.op = TR_OP_FUNC_CALL; A.leaf[0] = copyNode(func_name); A.leaf[1] = copyNode(B); A.valid=1; }
|
||||
expr(A) ::= G_PARENL expr(B) G_PARENR. { A.op = B.op; A.value = B.value; A.valid=B.valid; A.leaf[0] = B.leaf[0]; A.leaf[1] = B.leaf[1]; A.srcPos = pEval->GetSourcePos(); }
|
||||
expr(A) ::= G_IDENTIFIER(F) G_PARENL expr(B) G_PARENR. { A.op = TR_OP_FUNC_CALL; A.leaf[0] = copyNode(F); A.leaf[1] = copyNode(B); A.valid = true; A.srcPos = pEval->GetSourcePos(); }
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
|
@ -67,18 +68,20 @@ static const std::string formatOpName( int op )
|
|||
{
|
||||
int op;
|
||||
std::string mnemonic;
|
||||
} simpleOps[] = { { TR_OP_MUL, "MUL" }, { TR_OP_DIV, "DIV" }, { TR_OP_ADD, "ADD" },
|
||||
}
|
||||
simpleOps[] =
|
||||
{
|
||||
{ TR_OP_MUL, "MUL" }, { TR_OP_DIV, "DIV" }, { TR_OP_ADD, "ADD" },
|
||||
{ TR_OP_SUB, "SUB" }, { TR_OP_LESS, "LESS" }, { TR_OP_GREATER, "GREATER" },
|
||||
{ TR_OP_LESS_EQUAL, "LESS_EQUAL" }, { TR_OP_GREATER_EQUAL, "GREATER_EQUAL" },
|
||||
{ TR_OP_EQUAL, "EQUAL" }, { TR_OP_NOT_EQUAL, "NEQUAL" }, { TR_OP_BOOL_AND, "AND" },
|
||||
{ TR_OP_BOOL_OR, "OR" }, { TR_OP_BOOL_NOT, "NOT" }, { -1, "" } };
|
||||
{ TR_OP_BOOL_OR, "OR" }, { TR_OP_BOOL_NOT, "NOT" }, { -1, "" }
|
||||
};
|
||||
|
||||
for( int i = 0; simpleOps[i].op >= 0; i++ )
|
||||
{
|
||||
if( simpleOps[i].op == op )
|
||||
{
|
||||
return simpleOps[i].mnemonic;
|
||||
}
|
||||
}
|
||||
|
||||
return "???";
|
||||
|
@ -87,32 +90,40 @@ static const std::string formatOpName( int op )
|
|||
|
||||
std::string UOP::Format() const
|
||||
{
|
||||
char str[1024];
|
||||
char str[LIBEVAL_MAX_LITERAL_LENGTH];
|
||||
|
||||
switch( m_op )
|
||||
{
|
||||
case TR_UOP_PUSH_VAR:
|
||||
sprintf( str, "PUSH VAR [%p]", m_arg );
|
||||
snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH VAR [%p]", m_arg );
|
||||
break;
|
||||
|
||||
case TR_UOP_PUSH_VALUE:
|
||||
{
|
||||
auto val = reinterpret_cast<VALUE*>( m_arg );
|
||||
if( val->GetType() == VT_NUMERIC )
|
||||
sprintf( str, "PUSH NUM [%.10f]", val->AsDouble() );
|
||||
VALUE* val = reinterpret_cast<VALUE*>( m_arg );
|
||||
|
||||
if( !val )
|
||||
snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH nullptr" );
|
||||
else if( val->GetType() == VT_NUMERIC )
|
||||
snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH NUM [%.10f]", val->AsDouble() );
|
||||
else
|
||||
sprintf( str, "PUSH STR [%s]", val->AsString().c_str() );
|
||||
break;
|
||||
snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH STR [%s]", val->AsString().c_str() );
|
||||
}
|
||||
break;
|
||||
|
||||
case TR_OP_METHOD_CALL:
|
||||
sprintf(str, "MCALL" );
|
||||
snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "MCALL" );
|
||||
break;
|
||||
|
||||
case TR_OP_FUNC_CALL:
|
||||
sprintf(str, "FCALL" );
|
||||
snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "FCALL" );
|
||||
break;
|
||||
|
||||
default:
|
||||
sprintf( str, "%s %d", formatOpName( m_op ).c_str(), m_op );
|
||||
snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "%s %d", formatOpName( m_op ).c_str(), m_op );
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
@ -140,7 +151,7 @@ std::string TOKENIZER::GetChars( std::function<bool( int )> cond ) const
|
|||
return rv;
|
||||
}
|
||||
|
||||
bool TOKENIZER::MatchAhead( std::string match, std::function<bool( int )> stopCond ) const
|
||||
bool TOKENIZER::MatchAhead( const std::string& match, std::function<bool( int )> stopCond ) const
|
||||
{
|
||||
int remaining = m_str.length() - m_pos;
|
||||
if( remaining < (int) match.length() )
|
||||
|
@ -158,11 +169,10 @@ COMPILER::COMPILER()
|
|||
{
|
||||
m_errorStatus.pendingError = false;
|
||||
m_localeDecimalSeparator = '.';
|
||||
m_parseFinished = false;
|
||||
m_unitResolver.reset( new UNIT_RESOLVER );
|
||||
m_sourcePos = 0;
|
||||
m_parseFinished = false;
|
||||
m_unitResolver = std::make_unique<UNIT_RESOLVER>();
|
||||
m_parser = LIBEVAL::ParseAlloc( malloc );
|
||||
m_parseError = false;
|
||||
m_parseErrorPos = 0;
|
||||
m_tree = nullptr;
|
||||
}
|
||||
|
||||
|
@ -207,7 +217,7 @@ bool COMPILER::Compile( const std::string& aString, UCODE* aCode )
|
|||
|
||||
newString( aString );
|
||||
m_errorStatus.pendingError = false;
|
||||
m_tree = nullptr;
|
||||
m_tree = nullptr;
|
||||
m_parseFinished = false;
|
||||
T_TOKEN tok;
|
||||
|
||||
|
@ -221,6 +231,8 @@ bool COMPILER::Compile( const std::string& aString, UCODE* aCode )
|
|||
|
||||
do
|
||||
{
|
||||
m_sourcePos = m_tokenizer.GetPos();
|
||||
|
||||
tok = getToken();
|
||||
libeval_dbg(10, "parse: tok %d\n", tok.token );
|
||||
Parse( m_parser, tok.token, tok.value, this );
|
||||
|
@ -228,9 +240,8 @@ bool COMPILER::Compile( const std::string& aString, UCODE* aCode )
|
|||
if( m_errorStatus.pendingError )
|
||||
{
|
||||
m_errorStatus.stage = ERROR_STATUS::CST_PARSE;
|
||||
m_errorStatus.failingPosition = m_tokenizer.GetPos();
|
||||
m_errorStatus.failingObject = tok.value.value.str;
|
||||
m_errorStatus.message = "Parse error";
|
||||
m_errorStatus.message.Printf( _( "Unrecognized token '%s'" ), tok.value.value.str );
|
||||
m_errorStatus.srcPos = m_tokenizer.GetPos();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -261,7 +272,6 @@ COMPILER::T_TOKEN COMPILER::getToken()
|
|||
bool done = false;
|
||||
do
|
||||
{
|
||||
|
||||
switch( m_lexerState )
|
||||
{
|
||||
case LS_DEFAULT:
|
||||
|
@ -280,7 +290,7 @@ COMPILER::T_TOKEN COMPILER::getToken()
|
|||
|
||||
bool COMPILER::lexString( COMPILER::T_TOKEN& aToken )
|
||||
{
|
||||
auto str = m_tokenizer.GetChars( []( int c ) -> bool { return c != '"'; } );
|
||||
auto str = m_tokenizer.GetChars( []( int c ) -> bool { return c != '\''; } );
|
||||
//printf("STR LIT '%s'\n", (const char *)str.c_str() );
|
||||
|
||||
aToken.token = G_STRING;
|
||||
|
@ -310,6 +320,7 @@ int COMPILER::resolveUnits()
|
|||
return -1;
|
||||
}
|
||||
|
||||
|
||||
bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken )
|
||||
{
|
||||
T_TOKEN retval;
|
||||
|
@ -326,38 +337,44 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken )
|
|||
return true;
|
||||
}
|
||||
|
||||
auto isDecimalSeparator = [&]( char ch ) -> bool {
|
||||
return ( ch == m_localeDecimalSeparator || ch == '.' || ch == ',' );
|
||||
};
|
||||
auto isDecimalSeparator =
|
||||
[&]( char ch ) -> bool
|
||||
{
|
||||
return ( ch == m_localeDecimalSeparator || ch == '.' || ch == ',' );
|
||||
};
|
||||
|
||||
// Lambda: get value as string, store into clToken.token and update current index.
|
||||
auto extractNumber = [&]() {
|
||||
bool haveSeparator = false;
|
||||
idx = 0;
|
||||
auto ch = m_tokenizer.GetChar();
|
||||
auto extractNumber =
|
||||
[&]()
|
||||
{
|
||||
bool haveSeparator = false;
|
||||
idx = 0;
|
||||
int ch = m_tokenizer.GetChar();
|
||||
|
||||
do
|
||||
{
|
||||
if( isDecimalSeparator( ch ) && haveSeparator )
|
||||
break;
|
||||
do
|
||||
{
|
||||
if( isDecimalSeparator( ch ) && haveSeparator )
|
||||
break;
|
||||
|
||||
current.append( 1, ch );
|
||||
current.append( 1, ch );
|
||||
|
||||
if( isDecimalSeparator( ch ) )
|
||||
haveSeparator = true;
|
||||
if( isDecimalSeparator( ch ) )
|
||||
haveSeparator = true;
|
||||
|
||||
m_tokenizer.NextChar();
|
||||
ch = m_tokenizer.GetChar();
|
||||
} while( isdigit( ch ) || isDecimalSeparator( ch ) );
|
||||
m_tokenizer.NextChar();
|
||||
ch = m_tokenizer.GetChar();
|
||||
} while( isdigit( ch ) || isDecimalSeparator( ch ) );
|
||||
|
||||
// Ensure that the systems decimal separator is used
|
||||
for( int i = current.length(); i; i-- )
|
||||
if( isDecimalSeparator( current[i - 1] ) )
|
||||
current[i - 1] = m_localeDecimalSeparator;
|
||||
// Ensure that the systems decimal separator is used
|
||||
for( int i = current.length(); i; i-- )
|
||||
{
|
||||
if( isDecimalSeparator( current[i - 1] ) )
|
||||
current[i - 1] = m_localeDecimalSeparator;
|
||||
}
|
||||
|
||||
|
||||
//printf("-> NUM: '%s'\n", (const char *) current.c_str() );
|
||||
};
|
||||
//printf("-> NUM: '%s'\n", (const char *) current.c_str() );
|
||||
};
|
||||
|
||||
|
||||
int ch;
|
||||
|
@ -398,7 +415,7 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken )
|
|||
retval.token = G_UNIT;
|
||||
retval.value.value.type = convertFrom;
|
||||
}
|
||||
else if( ch == '\"' ) // string literal
|
||||
else if( ch == '\'' ) // string literal
|
||||
{
|
||||
//printf( "MATCH STRING LITERAL\n" );
|
||||
m_lexerState = LS_STRING;
|
||||
|
@ -488,9 +505,8 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken )
|
|||
break;
|
||||
default:
|
||||
m_errorStatus.stage = ERROR_STATUS::CST_PARSE;
|
||||
m_errorStatus.failingPosition = m_tokenizer.GetPos();
|
||||
m_errorStatus.failingObject = ch;
|
||||
m_errorStatus.message = "Syntax error";
|
||||
m_errorStatus.message.Printf( _( "Unrecognized character '%c'" ), (char) ch );
|
||||
m_errorStatus.srcPos = m_tokenizer.GetPos();
|
||||
break; /* invalid character */
|
||||
}
|
||||
|
||||
|
@ -564,11 +580,10 @@ void dumpNode( std::string& buf, TREE_NODE* tok, int depth = 0 )
|
|||
|
||||
ERROR_STATUS COMPILER::GetErrorStatus()
|
||||
{
|
||||
ERROR_STATUS dummy;
|
||||
return dummy;
|
||||
return m_errorStatus;
|
||||
}
|
||||
|
||||
void COMPILER::ReportError( const std::string aErrorMsg )
|
||||
void COMPILER::ReportError( const std::string& aErrorMsg )
|
||||
{
|
||||
m_errorStatus.pendingError = true;
|
||||
m_errorStatus.message = aErrorMsg;
|
||||
|
@ -585,9 +600,10 @@ bool COMPILER::generateUCode( UCODE* aCode )
|
|||
std::vector<TREE_NODE*> stack;
|
||||
std::set<TREE_NODE*> visitedNodes;
|
||||
|
||||
auto visited = [&]( TREE_NODE* node ) -> bool {
|
||||
return visitedNodes.find( node ) != visitedNodes.end();
|
||||
};
|
||||
auto visited = [&]( TREE_NODE* node ) -> bool
|
||||
{
|
||||
return visitedNodes.find( node ) != visitedNodes.end();
|
||||
};
|
||||
|
||||
assert( m_tree );
|
||||
|
||||
|
@ -603,7 +619,7 @@ bool COMPILER::generateUCode( UCODE* aCode )
|
|||
|
||||
while( !stack.empty() )
|
||||
{
|
||||
auto node = stack.back();
|
||||
TREE_NODE* node = stack.back();
|
||||
|
||||
libeval_dbg( 4, "process node %p [op %d] [stack %lu]\n",
|
||||
node, node->op, (unsigned long)stack.size() );
|
||||
|
@ -623,47 +639,71 @@ bool COMPILER::generateUCode( UCODE* aCode )
|
|||
{
|
||||
case TR_IDENTIFIER:
|
||||
{
|
||||
auto vref = aCode->createVarRef( this, node->leaf[0]->value.str, node->leaf[1]->value.str );
|
||||
char* itemName = node->leaf[0]->value.str;
|
||||
char* propName = node->leaf[1]->value.str;
|
||||
VAR_REF* vref = aCode->createVarRef( this, itemName, propName );
|
||||
|
||||
if( m_errorStatus.pendingError )
|
||||
{
|
||||
libeval_dbg(4, "varref fail\n");
|
||||
m_errorStatus.pendingError = true;
|
||||
m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN;
|
||||
|
||||
if( m_errorStatus.message == "var" )
|
||||
{
|
||||
m_errorStatus.message.Printf( _( "Unrecognized item '%s'" ),
|
||||
itemName );
|
||||
m_errorStatus.srcPos = node->leaf[0]->srcPos - strlen( itemName );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_errorStatus.message.Printf( _( "Unrecognized property '%s'" ),
|
||||
propName );
|
||||
m_errorStatus.srcPos = node->leaf[1]->srcPos - strlen( propName );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
node->uop = makeUop( TR_UOP_PUSH_VAR, vref );
|
||||
node->isTerminal = true;
|
||||
break;
|
||||
}
|
||||
case TR_OP_FUNC_CALL:
|
||||
{
|
||||
char* itemName = node->leaf[0]->value.str;
|
||||
VAR_REF* vref = aCode->createVarRef( this, itemName, "" );
|
||||
|
||||
libeval_dbg(4, "got a method call... [%s], this = %s\n", node->leaf[1]->leaf[0]->value.str, node->leaf[0]->value.str);
|
||||
auto vref = aCode->createVarRef( this, node->leaf[0]->value.str, "");
|
||||
auto func = aCode->createFuncCall( this, node->leaf[1]->leaf[0]->value.str );
|
||||
if( m_errorStatus.pendingError )
|
||||
{
|
||||
m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN;
|
||||
m_errorStatus.message.Printf( _( "Unrecognized item '%s'" ), itemName );
|
||||
m_errorStatus.srcPos = node->leaf[0]->srcPos - strlen( itemName );
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!func)
|
||||
char* functionName = node->leaf[1]->leaf[0]->value.str;
|
||||
auto func = aCode->createFuncCall( this, functionName );
|
||||
|
||||
if( !func )
|
||||
{
|
||||
m_errorStatus.pendingError = true;
|
||||
m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN;
|
||||
libeval_dbg(0, "unable to resolve func %s\n", node->leaf[1]->leaf[0]->value.str );
|
||||
m_errorStatus.message.Printf( _( "Unrecognized function '%s'" ),
|
||||
functionName );
|
||||
m_errorStatus.srcPos = node->leaf[1]->leaf[0]->srcPos + 1;
|
||||
return false;
|
||||
// fixme: generate a message
|
||||
}
|
||||
|
||||
// printf("cfc4 test\n");
|
||||
// func(nullptr, nullptr, nullptr);
|
||||
|
||||
visitedNodes.insert( node->leaf[0] );
|
||||
visitedNodes.insert( node->leaf[1]->leaf[0] );
|
||||
|
||||
node->uop = makeUop( TR_OP_METHOD_CALL, func, vref );
|
||||
node->isTerminal = false;
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TR_NUMBER:
|
||||
{
|
||||
|
@ -711,15 +751,15 @@ bool COMPILER::generateUCode( UCODE* aCode )
|
|||
}
|
||||
|
||||
visitedNodes.insert( node );
|
||||
|
||||
if(node->uop)
|
||||
aCode->AddOp(node->uop);
|
||||
stack.pop_back();
|
||||
|
||||
stack.pop_back();
|
||||
}
|
||||
|
||||
libeval_dbg(2,"DUMp: \n%s\n", aCode->Dump().c_str() );
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -734,8 +774,8 @@ void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode )
|
|||
auto value = ctx->AllocValue();
|
||||
value->Set( reinterpret_cast<VAR_REF*>( m_arg )->GetValue( ucode ) );
|
||||
ctx->Push( value );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case TR_UOP_PUSH_VALUE:
|
||||
ctx->Push( reinterpret_cast<VALUE*>( m_arg ) );
|
||||
|
@ -745,15 +785,16 @@ void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode )
|
|||
//printf("CALL METHOD %s\n" );
|
||||
m_func( ucode, ctx, m_arg );
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( m_op & TR_OP_BINARY_MASK )
|
||||
{
|
||||
auto arg2 = ctx->Pop();
|
||||
auto arg1 = ctx->Pop();
|
||||
double result;
|
||||
LIBEVAL::VALUE* arg2 = ctx->Pop();
|
||||
LIBEVAL::VALUE* arg1 = ctx->Pop();
|
||||
double result;
|
||||
|
||||
switch( m_op )
|
||||
{
|
||||
|
@ -815,30 +856,22 @@ void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
VALUE* UCODE::Run()
|
||||
{
|
||||
CONTEXT ctx;
|
||||
for( const auto op : m_ucode )
|
||||
|
||||
for( UOP* op : m_ucode )
|
||||
op->Exec( &ctx, this );
|
||||
|
||||
assert( ctx.SP() == 1 );
|
||||
return ctx.Pop();
|
||||
}
|
||||
|
||||
void UCODE::RuntimeError( const std::string aErrorMsg )
|
||||
|
||||
void UCODE::RuntimeError( const std::string& aErrorMsg )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string ERROR_STATUS::Format() const
|
||||
{
|
||||
if( !pendingError )
|
||||
return "";
|
||||
|
||||
char str[1024];
|
||||
sprintf(str,"%s (pos: %d, near: '%s')", message.c_str(), failingPosition, failingObject.c_str() );
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
} // namespace LIBEVAL
|
||||
|
|
|
@ -418,13 +418,26 @@ bool NET_SETTINGS::ParseBusGroup( wxString aGroup, wxString* aName,
|
|||
}
|
||||
|
||||
|
||||
void NET_SETTINGS::ResolveNetClassAssignments()
|
||||
void NET_SETTINGS::ResolveNetClassAssignments( bool aRebuildFromScratch )
|
||||
{
|
||||
std::map<wxString, wxString> existing = m_NetClassAssignments;
|
||||
std::map<wxString, wxString> baseList = m_NetClassAssignments;
|
||||
|
||||
if( aRebuildFromScratch )
|
||||
{
|
||||
for( const std::pair<const wxString, NETCLASSPTR>& netclass : m_NetClasses )
|
||||
{
|
||||
for( const wxString& net : *netclass.second )
|
||||
baseList[ net ] = netclass.second->GetName();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
baseList = m_NetClassAssignments;
|
||||
}
|
||||
|
||||
m_NetClassAssignments.clear();
|
||||
|
||||
for( const auto& ii : existing )
|
||||
for( const auto& ii : baseList )
|
||||
{
|
||||
m_NetClassAssignments[ ii.first ] = ii.second;
|
||||
|
||||
|
|
|
@ -44,8 +44,8 @@ const wxString& PROPERTY_MANAGER::ResolveType( TYPE_ID aType ) const
|
|||
|
||||
PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aProperty ) const
|
||||
{
|
||||
wxASSERT_MSG( !m_dirty, "Have not called PROPERTY_MANAGER::Rebuild(), "
|
||||
"property list not up-to-date" );
|
||||
if( m_dirty )
|
||||
const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
|
||||
|
||||
auto it = m_classes.find( aType );
|
||||
|
||||
|
@ -54,7 +54,7 @@ PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aPr
|
|||
|
||||
const CLASS_DESC& classDesc = it->second;
|
||||
|
||||
for( const auto& property : classDesc.m_allProperties )
|
||||
for( PROPERTY_BASE* property : classDesc.m_allProperties )
|
||||
{
|
||||
if( !aProperty.CmpNoCase( property->Name() ) )
|
||||
return property;
|
||||
|
@ -66,8 +66,8 @@ PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aPr
|
|||
|
||||
const PROPERTY_LIST& PROPERTY_MANAGER::GetProperties( TYPE_ID aType ) const
|
||||
{
|
||||
wxASSERT_MSG( !m_dirty, "Have not called PROPERTY_MANAGER::Rebuild(), "
|
||||
"property list not up-to-date" );
|
||||
if( m_dirty )
|
||||
const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
|
||||
|
||||
static const PROPERTY_LIST empty;
|
||||
auto it = m_classes.find( aType );
|
||||
|
@ -138,7 +138,7 @@ void PROPERTY_MANAGER::InheritsAfter( TYPE_ID aDerived, TYPE_ID aBase )
|
|||
m_dirty = true;
|
||||
|
||||
wxASSERT_MSG( derived.m_bases.size() == 1 || derived.m_typeCasts.count( aBase ) == 1,
|
||||
"You need to add a TYPE_CAST for classes inheriting from multiple bases" );
|
||||
"You need to add a TYPE_CAST for classes inheriting from multiple bases" );
|
||||
}
|
||||
|
||||
|
||||
|
@ -163,12 +163,8 @@ bool PROPERTY_MANAGER::IsOfType( TYPE_ID aDerived, TYPE_ID aBase ) const
|
|||
|
||||
void PROPERTY_MANAGER::Rebuild()
|
||||
{
|
||||
wxASSERT_MSG( m_dirty, "Excessive Rebuild() call" );
|
||||
|
||||
for( auto& classEntry : m_classes )
|
||||
{
|
||||
for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
|
||||
classEntry.second.rebuild();
|
||||
}
|
||||
|
||||
m_dirty = false;
|
||||
}
|
||||
|
@ -195,28 +191,31 @@ void PROPERTY_MANAGER::CLASS_DESC::rebuild()
|
|||
}
|
||||
|
||||
|
||||
void PROPERTY_MANAGER::CLASS_DESC::collectPropsRecur( PROPERTY_LIST& aResult, PROPERTY_SET& aReplaced ) const
|
||||
void PROPERTY_MANAGER::CLASS_DESC::collectPropsRecur( PROPERTY_LIST& aResult,
|
||||
PROPERTY_SET& aReplaced ) const
|
||||
{
|
||||
for( const auto& replacedEntry : m_replaced )
|
||||
for( const std::pair<size_t, wxString>& replacedEntry : m_replaced )
|
||||
aReplaced.emplace( replacedEntry );
|
||||
|
||||
for( auto& propertyData : m_ownProperties )
|
||||
for( const std::pair<const wxString, std::unique_ptr<PROPERTY_BASE>>& prop : m_ownProperties )
|
||||
{
|
||||
PROPERTY_BASE* property = propertyData.second.get();
|
||||
PROPERTY_BASE* property = prop.second.get();
|
||||
|
||||
// Do not store replaced properties
|
||||
if( aReplaced.count( std::make_pair( property->OwnerHash(), property->Name() ) ) == 0 )
|
||||
aResult.push_back( property );
|
||||
}
|
||||
|
||||
for( const auto& base : m_bases )
|
||||
for( const std::reference_wrapper<CLASS_DESC>& base : m_bases )
|
||||
base.get().collectPropsRecur( aResult, aReplaced );
|
||||
}
|
||||
|
||||
|
||||
std::vector<TYPE_ID> PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aProperty )
|
||||
{
|
||||
std::vector<TYPE_ID> ids;
|
||||
|
||||
|
||||
/*
|
||||
for( auto& cls : m_classes )
|
||||
{
|
||||
CLASS_INFO info;
|
||||
|
@ -224,26 +223,29 @@ std::vector<TYPE_ID> PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aPrope
|
|||
for( auto prop : cls.second.m_allProperties )
|
||||
info.properties.push_back(prop);
|
||||
|
||||
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
|
||||
PROPERTY_MANAGER::CLASSES_INFO PROPERTY_MANAGER::GetAllClasses()
|
||||
{
|
||||
CLASSES_INFO rv;
|
||||
for( auto& cls : m_classes )
|
||||
|
||||
for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
|
||||
{
|
||||
CLASS_INFO info;
|
||||
|
||||
info.type = cls.first;
|
||||
info.name = m_classNames[cls.first];
|
||||
info.type = classEntry.first;
|
||||
info.name = m_classNames[classEntry.first];
|
||||
|
||||
for( auto prop : cls.second.m_allProperties )
|
||||
info.properties.push_back(prop);
|
||||
for( PROPERTY_BASE* prop : classEntry.second.m_allProperties )
|
||||
info.properties.push_back( prop );
|
||||
|
||||
rv.push_back(info);
|
||||
rv.push_back( info );
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
|
|
@ -268,7 +268,7 @@ void SCH_EDIT_FRAME::ShowSchematicSetupDialog( const wxString& aInitialPage )
|
|||
|
||||
if( dlg.ShowQuasiModal() == wxID_OK )
|
||||
{
|
||||
Prj().GetProjectFile().NetSettings().ResolveNetClassAssignments();
|
||||
Prj().GetProjectFile().NetSettings().ResolveNetClassAssignments( true );
|
||||
SaveProjectSettings();
|
||||
|
||||
Kiway().CommonSettingsChanged( false, true );
|
||||
|
|
|
@ -219,14 +219,6 @@ public:
|
|||
std::vector<VIA_DIMENSION> m_ViasDimensionsList;
|
||||
std::vector<DIFF_PAIR_DIMENSION> m_DiffPairDimensionsList;
|
||||
|
||||
// List of netclasses. There is always the default netclass.
|
||||
//NETCLASSES m_NetClasses;
|
||||
std::vector<DRC_SELECTOR*> m_DRCRuleSelectors;
|
||||
std::vector<DRC_RULE*> m_DRCRules;
|
||||
|
||||
// Temporary storage for rule matching.
|
||||
std::vector<DRC_SELECTOR*> m_matched;
|
||||
|
||||
bool m_MicroViasAllowed; ///< true to allow micro vias
|
||||
bool m_BlindBuriedViaAllowed; ///< true to allow blind/buried vias
|
||||
VIATYPE m_CurrentViaType; ///< (VIA_BLIND_BURIED, VIA_THROUGH, VIA_MICROVIA)
|
||||
|
@ -243,10 +235,9 @@ public:
|
|||
int m_CopperEdgeClearance;
|
||||
int m_HoleToHoleMin; // Min width of peninsula between two drilled holes
|
||||
|
||||
std::map< int, int > m_DRCSeverities; // Map from DRCErrorCode to SEVERITY
|
||||
|
||||
/// Excluded DRC items
|
||||
std::set<wxString> m_DrcExclusions;
|
||||
std::vector<DRC_RULE*> m_DRCRules;
|
||||
std::map< int, int > m_DRCSeverities; // Map from DRCErrorCode to SEVERITY
|
||||
std::set<wxString> m_DrcExclusions;
|
||||
|
||||
/** Option to handle filled polygons in zones:
|
||||
* the "legacy" option is using thick outlines around filled polygons: give the best shape
|
||||
|
|
|
@ -354,4 +354,49 @@ protected:
|
|||
DECLARE_ENUM_TO_WXANY( PCB_LAYER_ID );
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* A singleton item of this class is returned for a weak reference that no longer exists.
|
||||
* Its sole purpose is to flag the item as having been deleted.
|
||||
*/
|
||||
class DELETED_BOARD_ITEM : public BOARD_ITEM
|
||||
{
|
||||
public:
|
||||
DELETED_BOARD_ITEM() :
|
||||
BOARD_ITEM( nullptr, NOT_USED )
|
||||
{}
|
||||
|
||||
wxString GetSelectMenuText( EDA_UNITS aUnits ) const override
|
||||
{
|
||||
return _( "(Deleted Item)" );
|
||||
}
|
||||
|
||||
wxString GetClass() const override
|
||||
{
|
||||
return wxT( "DELETED_BOARD_ITEM" );
|
||||
}
|
||||
|
||||
// pure virtuals:
|
||||
void SetPosition( const wxPoint& ) override {}
|
||||
|
||||
wxPoint GetPosition() const override {
|
||||
return wxPoint(0, 0);
|
||||
}
|
||||
|
||||
static DELETED_BOARD_ITEM* GetInstance()
|
||||
{
|
||||
static DELETED_BOARD_ITEM* item = nullptr;
|
||||
|
||||
if( !item )
|
||||
item = new DELETED_BOARD_ITEM();
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int , std::ostream& ) const override {}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#endif /* BOARD_ITEM_STRUCT_H */
|
||||
|
|
|
@ -57,20 +57,18 @@ class COMPILER;
|
|||
|
||||
struct ERROR_STATUS
|
||||
{
|
||||
bool pendingError;
|
||||
bool pendingError;
|
||||
|
||||
enum STAGE {
|
||||
CST_PARSE = 0,
|
||||
CST_CODEGEN,
|
||||
CST_RUNTIME
|
||||
};
|
||||
enum STAGE
|
||||
{
|
||||
CST_PARSE = 0,
|
||||
CST_CODEGEN,
|
||||
CST_RUNTIME
|
||||
};
|
||||
|
||||
STAGE stage;
|
||||
std::string message;
|
||||
std::string failingObject;
|
||||
int failingPosition;
|
||||
|
||||
std::string Format() const;
|
||||
STAGE stage;
|
||||
wxString message; // Note: use wxString for GUI-related strings
|
||||
int srcPos;
|
||||
};
|
||||
|
||||
|
||||
|
@ -108,158 +106,155 @@ struct TREE_NODE
|
|||
UOP* uop;
|
||||
bool valid;
|
||||
bool isTerminal;
|
||||
int srcPos;
|
||||
};
|
||||
|
||||
|
||||
static inline TREE_NODE* copyNode( TREE_NODE& t )
|
||||
{
|
||||
auto t2 = new TREE_NODE();
|
||||
t2->valid = t.valid;
|
||||
auto t2 = new TREE_NODE();
|
||||
t2->valid = t.valid;
|
||||
snprintf( t2->value.str, LIBEVAL_MAX_LITERAL_LENGTH, "%s", t.value.str );
|
||||
t2->op = t.op;
|
||||
t2->value.type = t.value.type;
|
||||
t2->leaf[0] = t.leaf[0];
|
||||
t2->leaf[1] = t.leaf[1];
|
||||
t2->isTerminal = false;
|
||||
t2->uop = nullptr;
|
||||
t2->op = t.op;
|
||||
t2->value.type = t.value.type;
|
||||
t2->leaf[0] = t.leaf[0];
|
||||
t2->leaf[1] = t.leaf[1];
|
||||
t2->isTerminal = false;
|
||||
t2->srcPos = t.srcPos;
|
||||
t2->uop = nullptr;
|
||||
return t2;
|
||||
}
|
||||
|
||||
|
||||
static inline TREE_NODE* newNode( int op, int type, const std::string& value )
|
||||
{
|
||||
auto t2 = new TREE_NODE();
|
||||
t2->valid = true;
|
||||
auto t2 = new TREE_NODE();
|
||||
t2->valid = true;
|
||||
snprintf( t2->value.str, LIBEVAL_MAX_LITERAL_LENGTH, "%s", value.c_str() );
|
||||
t2->op = op;
|
||||
t2->value.type = type;
|
||||
t2->leaf[0] = nullptr;
|
||||
t2->leaf[1] = nullptr;
|
||||
t2->isTerminal = false;
|
||||
t2->uop = nullptr;
|
||||
t2->op = op;
|
||||
t2->value.type = type;
|
||||
t2->leaf[0] = nullptr;
|
||||
t2->leaf[1] = nullptr;
|
||||
t2->isTerminal = false;
|
||||
t2->srcPos = -1;
|
||||
t2->uop = nullptr;
|
||||
return t2;
|
||||
}
|
||||
|
||||
|
||||
class UNIT_RESOLVER {
|
||||
public:
|
||||
UNIT_RESOLVER()
|
||||
{
|
||||
}
|
||||
class UNIT_RESOLVER
|
||||
{
|
||||
public:
|
||||
UNIT_RESOLVER()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~UNIT_RESOLVER()
|
||||
{
|
||||
}
|
||||
virtual ~UNIT_RESOLVER()
|
||||
{
|
||||
}
|
||||
|
||||
virtual const std::vector<std::string>& GetSupportedUnits() const
|
||||
{
|
||||
static const std::vector<std::string> nullUnits;
|
||||
virtual const std::vector<std::string>& GetSupportedUnits() const
|
||||
{
|
||||
static const std::vector<std::string> nullUnits;
|
||||
|
||||
return nullUnits;
|
||||
}
|
||||
return nullUnits;
|
||||
}
|
||||
|
||||
virtual double Convert( const std::string aString, int unitType ) const
|
||||
{
|
||||
return 0.0;
|
||||
};
|
||||
virtual double Convert( const std::string& aString, int unitType ) const
|
||||
{
|
||||
return 0.0;
|
||||
};
|
||||
};
|
||||
|
||||
class VALUE {
|
||||
|
||||
class VALUE
|
||||
{
|
||||
public:
|
||||
VALUE():
|
||||
m_type(VT_UNDEFINED),
|
||||
m_valueDbl( 0 )
|
||||
{};
|
||||
{};
|
||||
|
||||
VALUE( const std::string& aStr ) :
|
||||
VALUE( std::string aStr ) :
|
||||
m_type( VT_STRING ),
|
||||
m_valueDbl( 0 ),
|
||||
m_valueStr( aStr )
|
||||
{};
|
||||
m_valueStr( std::move( aStr ) )
|
||||
{};
|
||||
|
||||
VALUE( const double aVal ) :
|
||||
m_type( VT_NUMERIC ),
|
||||
m_valueDbl( aVal )
|
||||
{};
|
||||
{};
|
||||
|
||||
double AsDouble() const
|
||||
{
|
||||
return m_valueDbl;
|
||||
}
|
||||
double AsDouble() const
|
||||
{
|
||||
return m_valueDbl;
|
||||
}
|
||||
|
||||
const std::string& AsString() const
|
||||
{
|
||||
return m_valueStr;
|
||||
}
|
||||
const std::string& AsString() const
|
||||
{
|
||||
return m_valueStr;
|
||||
}
|
||||
|
||||
bool operator==( const VALUE& b ) const
|
||||
{
|
||||
if( m_type != b.m_type )
|
||||
return false;
|
||||
if( m_type == VT_NUMERIC && m_valueDbl != b.m_valueDbl )
|
||||
return false;
|
||||
if( m_type == VT_STRING && m_valueStr != b.m_valueStr )
|
||||
return false;
|
||||
bool operator==( const VALUE& b ) const
|
||||
{
|
||||
if( m_type == VT_NUMERIC && b.m_type == VT_NUMERIC )
|
||||
return m_valueDbl == b.m_valueDbl;
|
||||
else if( m_type == VT_STRING && b.m_type == VT_STRING )
|
||||
return m_valueStr == b.m_valueStr;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
VAR_TYPE_T GetType() const { return m_type; };
|
||||
|
||||
VAR_TYPE_T GetType() const { return m_type; };
|
||||
void Set( double aValue )
|
||||
{
|
||||
m_type = VT_NUMERIC;
|
||||
m_valueDbl = aValue;
|
||||
}
|
||||
|
||||
void Set( double aValue )
|
||||
{
|
||||
m_type = VT_NUMERIC;
|
||||
m_valueDbl = aValue;
|
||||
}
|
||||
void Set( const std::string& aValue )
|
||||
{
|
||||
m_type = VT_STRING;
|
||||
m_valueStr = aValue;
|
||||
}
|
||||
|
||||
void Set( std::string aValue )
|
||||
{
|
||||
m_type = VT_STRING;
|
||||
m_valueStr = aValue;
|
||||
}
|
||||
void Set( const VALUE &val )
|
||||
{
|
||||
m_type = val.m_type;
|
||||
m_valueDbl = val.m_valueDbl;
|
||||
|
||||
void Set( const VALUE &val )
|
||||
{
|
||||
m_type = val.m_type;
|
||||
m_valueDbl = val.m_valueDbl;
|
||||
if(m_type == VT_STRING)
|
||||
if( m_type == VT_STRING )
|
||||
m_valueStr = val.m_valueStr;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool EqualTo( const VALUE* v2 ) const
|
||||
{
|
||||
assert ( m_type == v2->m_type );
|
||||
if(m_type == VT_STRING)
|
||||
return m_valueStr == v2->m_valueStr;
|
||||
else
|
||||
return m_valueDbl == v2->m_valueDbl;
|
||||
}
|
||||
bool EqualTo( const VALUE* v2 ) const
|
||||
{
|
||||
return operator==( *v2 );
|
||||
}
|
||||
|
||||
private:
|
||||
VAR_TYPE_T m_type;
|
||||
double m_valueDbl;
|
||||
std::string m_valueStr;
|
||||
};
|
||||
VAR_TYPE_T m_type;
|
||||
double m_valueDbl;
|
||||
std::string m_valueStr;
|
||||
};
|
||||
|
||||
|
||||
class UCODE;
|
||||
|
||||
class VAR_REF
|
||||
{
|
||||
public:
|
||||
virtual VAR_TYPE_T GetType( UCODE* aUcode ) = 0;
|
||||
virtual VALUE GetValue( UCODE* aUcode ) = 0;
|
||||
};
|
||||
{
|
||||
public:
|
||||
virtual VAR_TYPE_T GetType() = 0;
|
||||
virtual VALUE GetValue( UCODE* aUcode ) = 0;
|
||||
};
|
||||
|
||||
|
||||
class UCODE
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
class CONTEXT
|
||||
{
|
||||
public:
|
||||
|
@ -268,7 +263,8 @@ public:
|
|||
CONTEXT()
|
||||
{
|
||||
m_sp = 0;
|
||||
for (int i = 0; i < c_memSize; i++ )
|
||||
|
||||
for( int i = 0; i < c_memSize; i++ )
|
||||
m_memory.push_back( VALUE() );
|
||||
}
|
||||
|
||||
|
@ -294,11 +290,12 @@ public:
|
|||
{
|
||||
return m_sp;
|
||||
}
|
||||
private:
|
||||
std::vector<VALUE> m_memory;
|
||||
VALUE* m_stack[128];
|
||||
int m_sp = 0;
|
||||
int m_memPos = 0;
|
||||
|
||||
private:
|
||||
std::vector<VALUE> m_memory;
|
||||
VALUE* m_stack[128];
|
||||
int m_sp = 0;
|
||||
int m_memPos = 0;
|
||||
};
|
||||
|
||||
typedef std::function<void(UCODE*, CONTEXT*, void*)> FUNC_PTR;
|
||||
|
@ -310,7 +307,7 @@ public:
|
|||
|
||||
VALUE* Run();
|
||||
std::string Dump() const;
|
||||
void RuntimeError( const std::string aErrorMsg );
|
||||
void RuntimeError( const std::string& aErrorMsg );
|
||||
|
||||
virtual VAR_REF* createVarRef( COMPILER* aCompiler, const std::string& var, const std::string& field )
|
||||
{
|
||||
|
@ -328,21 +325,28 @@ private:
|
|||
|
||||
|
||||
class UOP
|
||||
{
|
||||
public:
|
||||
UOP( int op, void* arg ) : m_op( op ), m_arg( arg )
|
||||
{};
|
||||
UOP( int op, UCODE::FUNC_PTR func, void *arg ) : m_op( op ), m_arg(arg), m_func( func )
|
||||
{};
|
||||
{
|
||||
public:
|
||||
UOP( int op, void* arg ) :
|
||||
m_op( op ),
|
||||
m_arg( arg )
|
||||
{};
|
||||
|
||||
void Exec( UCODE::CONTEXT* ctx, UCODE *ucode );
|
||||
std::string Format() const;
|
||||
UOP( int op, UCODE::FUNC_PTR func, void *arg ) :
|
||||
m_op( op ),
|
||||
m_arg(arg),
|
||||
m_func( std::move( func ) )
|
||||
{};
|
||||
|
||||
private:
|
||||
int m_op;
|
||||
void *m_arg;
|
||||
UCODE::FUNC_PTR m_func;
|
||||
};
|
||||
void Exec( UCODE::CONTEXT* ctx, UCODE *ucode );
|
||||
|
||||
std::string Format() const;
|
||||
|
||||
private:
|
||||
int m_op;
|
||||
void* m_arg;
|
||||
UCODE::FUNC_PTR m_func;
|
||||
};
|
||||
|
||||
class TOKENIZER
|
||||
{
|
||||
|
@ -363,6 +367,7 @@ public:
|
|||
{
|
||||
if( m_pos >= m_str.length() )
|
||||
return 0;
|
||||
|
||||
return m_str[m_pos];
|
||||
}
|
||||
|
||||
|
@ -381,13 +386,13 @@ public:
|
|||
return m_pos;
|
||||
}
|
||||
|
||||
|
||||
std::string GetChars( std::function<bool( int )> cond ) const;
|
||||
bool MatchAhead( std::string match, std::function<bool( int )> stopCond ) const;
|
||||
|
||||
bool MatchAhead( const std::string& match, std::function<bool( int )> stopCond ) const;
|
||||
|
||||
private:
|
||||
std::string m_str;
|
||||
size_t m_pos;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -397,7 +402,8 @@ public:
|
|||
COMPILER();
|
||||
virtual ~COMPILER();
|
||||
|
||||
/* clear() should be invoked by the client if a new input string is to be processed. It
|
||||
/*
|
||||
* clear() should be invoked by the client if a new input string is to be processed. It
|
||||
* will reset the parser. User defined variables are retained.
|
||||
*/
|
||||
void Clear();
|
||||
|
@ -406,17 +412,18 @@ public:
|
|||
void parseError( const char* s );
|
||||
void parseOk();
|
||||
|
||||
int GetSourcePos() const { return m_sourcePos; }
|
||||
|
||||
/* Check if previous invokation of process() was successful */
|
||||
inline bool IsValid() const
|
||||
{
|
||||
return !m_errorStatus.pendingError;
|
||||
}
|
||||
|
||||
void setRoot( LIBEVAL::TREE_NODE root );
|
||||
|
||||
void setRoot( LIBEVAL::TREE_NODE root );
|
||||
|
||||
bool Compile( const std::string& aString, UCODE* aCode );
|
||||
std::string DumpTree();
|
||||
void ReportError( const std::string aErrorMsg );
|
||||
void ReportError( const std::string& aErrorMsg );
|
||||
ERROR_STATUS GetErrorStatus();
|
||||
|
||||
protected:
|
||||
|
@ -446,9 +453,6 @@ protected:
|
|||
bool lexDefault( T_TOKEN& aToken );
|
||||
bool lexString( T_TOKEN& aToken );
|
||||
|
||||
/* Used by processing loop */
|
||||
void parse( int token, TREE_NODE value );
|
||||
|
||||
int resolveUnits();
|
||||
|
||||
UOP* makeUop( int op, double value )
|
||||
|
@ -459,40 +463,35 @@ protected:
|
|||
|
||||
UOP* makeUop( int op, std::string value )
|
||||
{
|
||||
auto uop = new UOP( op, new VALUE( value ) );
|
||||
UOP* uop = new UOP( op, new VALUE( std::move( value ) ) );
|
||||
return uop;
|
||||
}
|
||||
|
||||
UOP* makeUop( int op, VAR_REF* aRef = nullptr )
|
||||
{
|
||||
auto uop = new UOP( op, aRef );
|
||||
UOP* uop = new UOP( op, aRef );
|
||||
return uop;
|
||||
}
|
||||
|
||||
UOP* makeUop( int op, UCODE::FUNC_PTR aFunc, void *arg = nullptr )
|
||||
{
|
||||
auto uop = new UOP( op, aFunc, arg );
|
||||
UOP* uop = new UOP( op, std::move( aFunc ), arg );
|
||||
return uop;
|
||||
}
|
||||
|
||||
|
||||
/* Token state for input string. */
|
||||
|
||||
void* m_parser; // the current lemon parser state machine
|
||||
TOKENIZER m_tokenizer;
|
||||
char m_localeDecimalSeparator;
|
||||
|
||||
/* Parse progress. Set by parser actions. */
|
||||
bool m_parseError;
|
||||
bool m_parseFinished;
|
||||
std::string m_parseErrorMessage;
|
||||
std::string m_parseErrorToken;
|
||||
int m_parseErrorPos;
|
||||
void* m_parser; // the current lemon parser state machine
|
||||
TOKENIZER m_tokenizer;
|
||||
char m_localeDecimalSeparator;
|
||||
|
||||
std::unique_ptr<UNIT_RESOLVER> m_unitResolver;
|
||||
ERROR_STATUS m_errorStatus;
|
||||
|
||||
TREE_NODE* m_tree;
|
||||
int m_sourcePos;
|
||||
ERROR_STATUS m_errorStatus;
|
||||
bool m_parseFinished;
|
||||
|
||||
TREE_NODE* m_tree;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -77,8 +77,11 @@ public:
|
|||
/**
|
||||
* Explodes the list of netclass assignments to include atomic members of composite labels
|
||||
* (buses).
|
||||
*
|
||||
* @param aRebuildFromScratch indicates the assignments should be rebuilt from the netclass
|
||||
* membership lists before resolving.
|
||||
*/
|
||||
void ResolveNetClassAssignments();
|
||||
void ResolveNetClassAssignments( bool aRebuildFromScratch = false );
|
||||
|
||||
private:
|
||||
// TODO: Add diff pairs, bus information, etc here.
|
||||
|
|
|
@ -526,6 +526,11 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
void SetDefault( T aValue )
|
||||
{
|
||||
m_default = aValue;
|
||||
}
|
||||
|
||||
const wxString& ToString( T value ) const
|
||||
{
|
||||
return m_choices.GetLabel( static_cast<int>( value ) );
|
||||
|
@ -533,7 +538,10 @@ public:
|
|||
|
||||
const T ToEnum( const wxString value )
|
||||
{
|
||||
return m_reverseMap[value];
|
||||
if( m_reverseMap.count( value ) )
|
||||
return m_reverseMap[ value ];
|
||||
else
|
||||
return m_default;
|
||||
}
|
||||
|
||||
const wxPGChoices& Choices() const
|
||||
|
@ -542,8 +550,9 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
wxPGChoices m_choices;
|
||||
wxPGChoices m_choices;
|
||||
std::unordered_map<wxString, T> m_reverseMap;
|
||||
T m_default; // Returned if the string is not recognized
|
||||
|
||||
ENUM_MAP<T>()
|
||||
{
|
||||
|
|
|
@ -204,14 +204,14 @@ static struct BOARD_CONNECTED_ITEM_DESC
|
|||
{
|
||||
BOARD_CONNECTED_ITEM_DESC()
|
||||
{
|
||||
auto& layerEnum = ENUM_MAP<PCB_LAYER_ID>::Instance();
|
||||
ENUM_MAP<PCB_LAYER_ID>& layerEnum = ENUM_MAP<PCB_LAYER_ID>::Instance();
|
||||
|
||||
if( layerEnum.Choices().GetCount() == 0 )
|
||||
{
|
||||
layerEnum.SetDefault( UNDEFINED_LAYER );
|
||||
|
||||
for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
|
||||
{
|
||||
layerEnum.Map( *seq, LSET::Name( *seq ) );
|
||||
}
|
||||
}
|
||||
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
|
|
|
@ -590,9 +590,7 @@ void BOARD_DESIGN_SETTINGS::initFromOther( const BOARD_DESIGN_SETTINGS& aOther )
|
|||
m_TrackWidthList = aOther.m_TrackWidthList;
|
||||
m_ViasDimensionsList = aOther.m_ViasDimensionsList;
|
||||
m_DiffPairDimensionsList = aOther.m_DiffPairDimensionsList;
|
||||
m_DRCRuleSelectors = aOther.m_DRCRuleSelectors;
|
||||
m_DRCRules = aOther.m_DRCRules;
|
||||
m_matched = aOther.m_matched;
|
||||
m_MicroViasAllowed = aOther.m_MicroViasAllowed;
|
||||
m_BlindBuriedViaAllowed = aOther.m_BlindBuriedViaAllowed;
|
||||
m_CurrentViaType = aOther.m_CurrentViaType;
|
||||
|
|
|
@ -48,52 +48,6 @@
|
|||
#include <ratsnest/ratsnest_data.h>
|
||||
#include <ratsnest/ratsnest_viewitem.h>
|
||||
|
||||
/**
|
||||
* A singleton item of this class is returned for a weak reference that no longer exists.
|
||||
* Its sole purpose is to flag the item as having been deleted.
|
||||
*/
|
||||
class DELETED_BOARD_ITEM : public BOARD_ITEM
|
||||
{
|
||||
public:
|
||||
DELETED_BOARD_ITEM() :
|
||||
BOARD_ITEM( nullptr, NOT_USED )
|
||||
{}
|
||||
|
||||
wxString GetSelectMenuText( EDA_UNITS aUnits ) const override
|
||||
{
|
||||
return _( "(Deleted Item)" );
|
||||
}
|
||||
|
||||
wxString GetClass() const override
|
||||
{
|
||||
return wxT( "DELETED_BOARD_ITEM" );
|
||||
}
|
||||
|
||||
// pure virtuals:
|
||||
void SetPosition( const wxPoint& ) override {}
|
||||
|
||||
wxPoint GetPosition() const override {
|
||||
return wxPoint(0, 0);
|
||||
}
|
||||
|
||||
static DELETED_BOARD_ITEM* GetInstance()
|
||||
{
|
||||
static DELETED_BOARD_ITEM* item = nullptr;
|
||||
|
||||
if( !item )
|
||||
item = new DELETED_BOARD_ITEM();
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Show( int , std::ostream& ) const override {}
|
||||
#endif
|
||||
};
|
||||
|
||||
DELETED_BOARD_ITEM* g_DeletedItem = nullptr;
|
||||
|
||||
|
||||
/* This is an odd place for this, but CvPcb won't link if it is
|
||||
* in class_board_item.cpp like I first tried it.
|
||||
*/
|
||||
|
|
|
@ -1,8 +1,3 @@
|
|||
/**
|
||||
* @file class_board_item.cpp
|
||||
* @brief Class BOARD_ITEM definition and some basic functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
|
@ -29,7 +24,6 @@
|
|||
*/
|
||||
|
||||
#include <fctsys.h>
|
||||
#include <common.h>
|
||||
#include <pcbnew.h>
|
||||
#include <wx/debug.h>
|
||||
|
||||
|
@ -137,8 +131,9 @@ void BOARD_ITEM::SwapData( BOARD_ITEM* aImage )
|
|||
}
|
||||
|
||||
|
||||
void BOARD_ITEM::TransformShapeWithClearanceToPolygon(
|
||||
SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const
|
||||
void BOARD_ITEM::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
|
||||
int aClearanceValue, int aError,
|
||||
bool ignoreLineWidth ) const
|
||||
{
|
||||
wxASSERT_MSG( false, "Called TransformShapeWithClearanceToPolygon() on unsupported BOARD_ITEM." );
|
||||
};
|
||||
|
@ -148,14 +143,14 @@ static struct BOARD_ITEM_DESC
|
|||
{
|
||||
BOARD_ITEM_DESC()
|
||||
{
|
||||
auto& layerEnum = ENUM_MAP<PCB_LAYER_ID>::Instance();
|
||||
ENUM_MAP<PCB_LAYER_ID>& layerEnum = ENUM_MAP<PCB_LAYER_ID>::Instance();
|
||||
|
||||
if( layerEnum.Choices().GetCount() == 0 )
|
||||
{
|
||||
layerEnum.SetDefault( UNDEFINED_LAYER );
|
||||
|
||||
for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
|
||||
{
|
||||
layerEnum.Map( *seq, LSET::Name( *seq ) );
|
||||
}
|
||||
}
|
||||
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
|
|
|
@ -1647,8 +1647,8 @@ static struct MODULE_DESC
|
|||
&MODULE::SetValue, &MODULE::GetValue ) );
|
||||
propMgr.AddProperty( new PROPERTY<MODULE, double>( _( "Orientation" ),
|
||||
&MODULE::SetOrientationDegrees, &MODULE::GetOrientationDegrees, PROPERTY_DISPLAY::DEGREE ) );
|
||||
//propMgr.AddProperty( new PROPERTY<MODULE, int>( _( "Local Clearance" ),
|
||||
// &MODULE::SetLocalClearance, &MODULE::GetLocalClearance, PROPERTY_DISPLAY::DISTANCE ) );
|
||||
propMgr.AddProperty( new PROPERTY<MODULE, int>( _( "Local Clearance" ),
|
||||
&MODULE::SetLocalClearance, &MODULE::GetLocalClearance, PROPERTY_DISPLAY::DISTANCE ) );
|
||||
propMgr.AddProperty( new PROPERTY<MODULE, int>( _( "Local Solderpaste Margin" ),
|
||||
&MODULE::SetLocalSolderPasteMargin, &MODULE::GetLocalSolderPasteMargin, PROPERTY_DISPLAY::DISTANCE ) );
|
||||
propMgr.AddProperty( new PROPERTY<MODULE, double>( _( "Local Solderpaste Margin Ratio" ),
|
||||
|
|
|
@ -237,7 +237,10 @@ public:
|
|||
int GetLocalSolderMaskMargin() const { return m_LocalSolderMaskMargin; }
|
||||
void SetLocalSolderMaskMargin( int aMargin ) { m_LocalSolderMaskMargin = aMargin; }
|
||||
|
||||
int GetLocalClearance( wxString* aSource = nullptr ) const
|
||||
int GetLocalClearance() const { return m_LocalClearance; }
|
||||
void SetLocalClearance( int aClearance ) { m_LocalClearance = aClearance; }
|
||||
|
||||
int GetLocalClearance( wxString* aSource ) const
|
||||
{
|
||||
if( aSource )
|
||||
*aSource = wxString::Format( _( "footprint %s" ), GetReference() );
|
||||
|
@ -245,8 +248,6 @@ public:
|
|||
return m_LocalClearance;
|
||||
}
|
||||
|
||||
void SetLocalClearance( int aClearance ) { m_LocalClearance = aClearance; }
|
||||
|
||||
int GetLocalSolderPasteMargin() const { return m_LocalSolderPasteMargin; }
|
||||
void SetLocalSolderPasteMargin( int aMargin ) { m_LocalSolderPasteMargin = aMargin; }
|
||||
|
||||
|
|
|
@ -36,8 +36,7 @@ PANEL_PCBNEW_COLOR_SETTINGS::PANEL_PCBNEW_COLOR_SETTINGS( PCB_EDIT_FRAME* aFrame
|
|||
: PANEL_COLOR_SETTINGS( aParent ),
|
||||
m_frame( aFrame ),
|
||||
m_page( nullptr ),
|
||||
m_titleBlock( nullptr ),
|
||||
m_ws( nullptr )
|
||||
m_titleBlock( nullptr )
|
||||
{
|
||||
// Currently this only applies to eeschema
|
||||
m_optOverrideColors->Hide();
|
||||
|
|
|
@ -61,8 +61,6 @@ private:
|
|||
|
||||
TITLE_BLOCK* m_titleBlock;
|
||||
|
||||
KIGFX::WS_PROXY_VIEW_ITEM* m_ws;
|
||||
|
||||
void createSwatches();
|
||||
};
|
||||
|
||||
|
|
|
@ -189,12 +189,11 @@ bool PANEL_SETUP_RULES::TransferDataFromWindow()
|
|||
|
||||
try
|
||||
{
|
||||
std::vector<DRC_SELECTOR*> dummySelectors;
|
||||
std::vector<DRC_RULE*> dummyRules;
|
||||
|
||||
DRC_RULES_PARSER parser( m_frame->GetBoard(), m_textEditor->GetText(), _( "DRC rules" ) );
|
||||
|
||||
parser.Parse( dummySelectors, dummyRules );
|
||||
parser.Parse( dummyRules );
|
||||
}
|
||||
catch( PARSE_ERROR& pe )
|
||||
{
|
||||
|
@ -249,7 +248,7 @@ void PANEL_SETUP_RULES::OnSyntaxHelp( wxHyperlinkEvent& aEvent )
|
|||
"<pre>"
|
||||
"(rule \"copper keepout\"\r"
|
||||
" (disallow track) (disallow via) (disallow zone)\r"
|
||||
" (condition \"A.name == no_copper\"))\r"
|
||||
" (condition \"A.name == 'no_copper'\"))\r"
|
||||
"\r"
|
||||
"(rule \"BGA neckdown\"\r"
|
||||
" (constraint track_width (min 0.2mm) (opt 0.25mm))\r"
|
||||
|
@ -258,11 +257,11 @@ void PANEL_SETUP_RULES::OnSyntaxHelp( wxHyperlinkEvent& aEvent )
|
|||
"\r"
|
||||
"(rule HV\r"
|
||||
" (constraint clearance (min 1.5mm))\r"
|
||||
" (condition \"A.netclass == HV\"))\r"
|
||||
" (condition \"A.netclass == 'HV'\"))\r"
|
||||
"\r"
|
||||
"(rule HV_HV\r"
|
||||
" (constraint clearance (min 2.0mm))\r"
|
||||
" (condition \"A.netclass == HV && B.netclass == HV\"))\r"
|
||||
" (condition \"A.netclass == 'HV' && B.netclass == 'HV'\"))\r"
|
||||
"</pre>";
|
||||
|
||||
HTML_MESSAGE_BOX dlg( m_parent, _( "Syntax Help" ) );
|
||||
|
|
|
@ -187,7 +187,6 @@ bool DRC::LoadRules()
|
|||
|
||||
if( rulesFile.FileExists() )
|
||||
{
|
||||
m_ruleSelectors.clear();
|
||||
m_rules.clear();
|
||||
|
||||
FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) );
|
||||
|
@ -197,12 +196,11 @@ bool DRC::LoadRules()
|
|||
try
|
||||
{
|
||||
DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath );
|
||||
parser.Parse( m_ruleSelectors, m_rules );
|
||||
parser.Parse( m_rules );
|
||||
}
|
||||
catch( PARSE_ERROR& pe )
|
||||
{
|
||||
// Don't leave possibly malformed stuff around for us to trip over
|
||||
m_ruleSelectors.clear();
|
||||
m_rules.clear();
|
||||
|
||||
wxSafeYield( m_editFrame );
|
||||
|
@ -214,10 +212,9 @@ bool DRC::LoadRules()
|
|||
}
|
||||
}
|
||||
|
||||
std::reverse( std::begin( m_ruleSelectors ), std::end( m_ruleSelectors ) );
|
||||
std::reverse( std::begin( m_rules ), std::end( m_rules ) );
|
||||
|
||||
BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
|
||||
bds.m_DRCRuleSelectors = m_ruleSelectors;
|
||||
bds.m_DRCRules = m_rules;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -132,7 +132,6 @@ private:
|
|||
bool m_drcRun; // indicates DRC has been run at least once
|
||||
bool m_footprintsTested; // indicates footprints were tested in last run
|
||||
|
||||
std::vector<DRC_SELECTOR*> m_ruleSelectors;
|
||||
std::vector<DRC_RULE*> m_rules;
|
||||
|
||||
// Temp variables for performance during a single DRC run
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <board_design_settings.h>
|
||||
#include <class_board.h>
|
||||
#include <class_board_item.h>
|
||||
#include <pcb_expr_evaluator.h>
|
||||
|
||||
|
||||
/*
|
||||
* Rule tokens:
|
||||
|
@ -52,8 +54,17 @@
|
|||
* hole
|
||||
*
|
||||
*
|
||||
* (rule "HV" (constraint clearance (min 200)))
|
||||
* (rule "HV_external" (constraint clearance (min 400)))
|
||||
* (rule "HV"
|
||||
* (constraint clearance (min 200))
|
||||
* (condition "A.Netclass == 'HV' || B.Netclass == 'HV'")
|
||||
* )
|
||||
*
|
||||
* (rule "HV_external"
|
||||
* (constraint clearance (min 400))
|
||||
* (condition "(A.Netclass == 'HV' && (A.onLayer('F.Cu') || A.onLayer('B.Cu'))
|
||||
* || (B.Netclass == 'HV' && (B.onLayer('F.Cu') || B.onLayer('B.Cu'))")
|
||||
* )
|
||||
*
|
||||
* (rule "HV2HV" (constraint clearance (min 200)))
|
||||
* (rule "HV2HV_external" (constraint clearance (min 500)))
|
||||
* (rule "pad2padHV" (constraint clearance (min 500)))
|
||||
|
@ -62,99 +73,83 @@
|
|||
* (rule "neckdown" (constraint clearance (min 15)))
|
||||
*
|
||||
* (rule "disallowMicrovias" (disallow micro_via))
|
||||
*
|
||||
*
|
||||
testEvalExpr( "A.type == \"Pad\" && B.type == \"Pad\" && (A.onLayer(\"F.Cu\"))",VAL(0.0), false, &trackA, &trackB );
|
||||
return 0;
|
||||
testEvalExpr( "A.Width > B.Width", VAL(0.0), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.Width + B.Width", VAL(Mils2iu(10) + Mils2iu(20)), false, &trackA, &trackB );
|
||||
|
||||
testEvalExpr( "A.Netclass", VAL( (const char*) trackA.GetNetClassName().c_str() ), false, &trackA, &trackB );
|
||||
testEvalExpr( "(A.Netclass == \"HV\") && (B.netclass == \"otherClass\") && (B.netclass != \"F.Cu\")", VAL( 1.0 ), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.Netclass + 1.0", VAL( 1.0 ), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.type == \"Track\" && B.type == \"Track\" && A.layer == \"F.Cu\"", VAL(0.0), false, &trackA, &trackB );
|
||||
testEvalExpr( "(A.type == \"Track\") && (B.type == \"Track\") && (A.layer == \"F.Cu\")", VAL(0.0), false, &trackA, &trackB );
|
||||
*/
|
||||
|
||||
DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint )
|
||||
{
|
||||
// JEY TODO: the bulk of this will be replaced by Tom's expression evaluator
|
||||
|
||||
BOARD* board = aItem->GetBoard();
|
||||
|
||||
if( !board )
|
||||
return nullptr;
|
||||
|
||||
NETCLASS* aNetclass = nullptr;
|
||||
NETCLASS* bNetclass = nullptr;
|
||||
|
||||
if( aItem->IsConnected() )
|
||||
aNetclass = static_cast<const BOARD_CONNECTED_ITEM*>( aItem )->GetEffectiveNetclass();
|
||||
|
||||
if( bItem && bItem->IsConnected() )
|
||||
bNetclass = static_cast<const BOARD_CONNECTED_ITEM*>( bItem )->GetEffectiveNetclass();
|
||||
|
||||
for( DRC_SELECTOR* candidate : board->GetDesignSettings().m_DRCRuleSelectors )
|
||||
for( DRC_RULE* rule : board->GetDesignSettings().m_DRCRules )
|
||||
{
|
||||
if( candidate->m_MatchNetclasses.size() == 2 )
|
||||
if( ( rule->m_ConstraintFlags & aConstraint ) > 0 )
|
||||
{
|
||||
if( !bItem )
|
||||
continue;
|
||||
|
||||
NETCLASS* firstNetclass = candidate->m_MatchNetclasses[0].get();
|
||||
NETCLASS* secondNetclass = candidate->m_MatchNetclasses[1].get();
|
||||
|
||||
if( !( aNetclass == firstNetclass && bNetclass == secondNetclass )
|
||||
&& !( aNetclass == secondNetclass && bNetclass == firstNetclass ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if( rule->m_Condition.EvaluateFor( aItem, bItem ) )
|
||||
return rule;
|
||||
}
|
||||
else if( candidate->m_MatchNetclasses.size() == 1 )
|
||||
{
|
||||
NETCLASS* matchNetclass = candidate->m_MatchNetclasses[0].get();
|
||||
|
||||
if( matchNetclass != aNetclass && !( bItem && matchNetclass == bNetclass ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
if( candidate->m_MatchTypes.size() == 2 )
|
||||
{
|
||||
if( !bItem )
|
||||
continue;
|
||||
|
||||
KICAD_T firstType[2] = { candidate->m_MatchTypes[0], EOT };
|
||||
KICAD_T secondType[2] = { candidate->m_MatchTypes[1], EOT };
|
||||
|
||||
if( !( aItem->IsType( firstType ) && bItem->IsType( secondType ) )
|
||||
&& !( aItem->IsType( secondType ) && bItem->IsType( firstType ) ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if( candidate->m_MatchTypes.size() == 1 )
|
||||
{
|
||||
KICAD_T matchType[2] = { candidate->m_MatchTypes[0], EOT };
|
||||
|
||||
if( !aItem->IsType( matchType ) && !( bItem && bItem->IsType( matchType ) ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
if( candidate->m_MatchLayers.size() )
|
||||
{
|
||||
PCB_LAYER_ID matchLayer = candidate->m_MatchLayers[0];
|
||||
|
||||
if( !aItem->GetLayerSet().test( matchLayer ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
if( candidate->m_MatchAreas.size() )
|
||||
{
|
||||
if( candidate->m_MatchAreas[0] == "$board" )
|
||||
{
|
||||
// matches everything
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: area/room matches...
|
||||
}
|
||||
}
|
||||
|
||||
// All tests done; if we're still here then it matches
|
||||
|
||||
if( ( candidate->m_Rule->m_ConstraintFlags & aConstraint ) > 0 )
|
||||
return candidate->m_Rule;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
DRC_RULE_CONDITION::DRC_RULE_CONDITION()
|
||||
{
|
||||
m_ucode = nullptr;
|
||||
}
|
||||
|
||||
|
||||
DRC_RULE_CONDITION::~DRC_RULE_CONDITION()
|
||||
{
|
||||
delete m_ucode;
|
||||
}
|
||||
|
||||
|
||||
bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB )
|
||||
{
|
||||
BOARD_ITEM* a = const_cast<BOARD_ITEM*>( aItemA );
|
||||
BOARD_ITEM* b = aItemB ? const_cast<BOARD_ITEM*>( aItemB ) : DELETED_BOARD_ITEM::GetInstance();
|
||||
|
||||
m_ucode->SetItems( a, b );
|
||||
|
||||
// fixme: handle error conditions
|
||||
return m_ucode->Run()->AsDouble() != 0.0;
|
||||
}
|
||||
|
||||
|
||||
bool DRC_RULE_CONDITION::Compile()
|
||||
{
|
||||
PCB_EXPR_COMPILER compiler;
|
||||
|
||||
if (!m_ucode)
|
||||
m_ucode = new PCB_EXPR_UCODE;
|
||||
|
||||
bool ok = compiler.Compile( (const char*) m_Expression.c_str(), m_ucode );
|
||||
|
||||
if( ok )
|
||||
return true;
|
||||
|
||||
m_compileError = compiler.GetErrorStatus();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
LIBEVAL::ERROR_STATUS DRC_RULE_CONDITION::GetCompilationError()
|
||||
{
|
||||
return m_compileError;
|
||||
}
|
||||
|
|
|
@ -27,9 +27,11 @@
|
|||
#include <core/typeinfo.h>
|
||||
#include <netclass.h>
|
||||
#include <layers_id_colors_and_visibility.h>
|
||||
#include <libeval_compiler/libeval_compiler.h>
|
||||
|
||||
|
||||
class BOARD_ITEM;
|
||||
class PCB_EXPR_UCODE;
|
||||
|
||||
|
||||
#define CLEARANCE_CONSTRAINT (1 << 0)
|
||||
|
@ -50,6 +52,52 @@ class BOARD_ITEM;
|
|||
#define DISALLOW_FOOTPRINTS (1 << 9)
|
||||
|
||||
|
||||
template<class T=int>
|
||||
class MINOPTMAX
|
||||
{
|
||||
public:
|
||||
T Min() const { assert( m_hasMin ); return m_min; };
|
||||
T Max() const { assert( m_hasMax ); return m_max; };
|
||||
T Opt() const { assert( m_hasOpt ); return m_opt; };
|
||||
|
||||
bool HasMin() const { return m_hasMin; }
|
||||
bool HasMax() const { return m_hasMax; }
|
||||
bool HasOpt() const { return m_hasOpt; }
|
||||
|
||||
void SetMin( T v ) { m_min = v; m_hasMin = true; }
|
||||
void SetMax( T v ) { m_max = v; m_hasMax = true; }
|
||||
void SetOpt( T v ) { m_opt = v; m_hasOpt = true; }
|
||||
|
||||
private:
|
||||
T m_min;
|
||||
T m_opt;
|
||||
T m_max;
|
||||
bool m_hasMin = false;
|
||||
bool m_hasOpt = false;
|
||||
bool m_hasMax = false;
|
||||
};
|
||||
|
||||
|
||||
class DRC_RULE_CONDITION
|
||||
{
|
||||
public:
|
||||
DRC_RULE_CONDITION();
|
||||
~DRC_RULE_CONDITION();
|
||||
|
||||
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB );
|
||||
bool Compile();
|
||||
LIBEVAL::ERROR_STATUS GetCompilationError();
|
||||
|
||||
public:
|
||||
wxString m_Expression;
|
||||
wxString m_TargetRuleName;
|
||||
|
||||
private:
|
||||
LIBEVAL::ERROR_STATUS m_compileError;
|
||||
PCB_EXPR_UCODE* m_ucode;
|
||||
};
|
||||
|
||||
|
||||
class DRC_RULE
|
||||
{
|
||||
public:
|
||||
|
@ -81,31 +129,11 @@ public:
|
|||
MINOPTMAX m_TrackConstraint;
|
||||
int m_MinHole;
|
||||
|
||||
wxString m_Condition;
|
||||
};
|
||||
|
||||
|
||||
class DRC_SELECTOR
|
||||
{
|
||||
public:
|
||||
DRC_SELECTOR() :
|
||||
m_Priority( 1 ),
|
||||
m_Rule( nullptr )
|
||||
{ }
|
||||
|
||||
public:
|
||||
std::vector<NETCLASSPTR> m_MatchNetclasses;
|
||||
std::vector<KICAD_T> m_MatchTypes;
|
||||
std::vector<PCB_LAYER_ID> m_MatchLayers;
|
||||
std::vector<wxString> m_MatchAreas;
|
||||
|
||||
int m_Priority; // 0 indicates automatic priority generation
|
||||
DRC_RULE* m_Rule;
|
||||
DRC_RULE_CONDITION m_Condition;
|
||||
};
|
||||
|
||||
|
||||
DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint );
|
||||
|
||||
|
||||
|
||||
#endif // DRC_RULE_H
|
||||
|
|
|
@ -65,10 +65,8 @@ void DRC_RULES_PARSER::initLayerMap()
|
|||
}
|
||||
|
||||
|
||||
void DRC_RULES_PARSER::Parse( std::vector<DRC_SELECTOR*>& aSelectors,
|
||||
std::vector<DRC_RULE*>& aRules )
|
||||
void DRC_RULES_PARSER::Parse( std::vector<DRC_RULE*>& aRules )
|
||||
{
|
||||
std::vector< std::pair<DRC_SELECTOR*, wxString> > selectorRules;
|
||||
bool haveVersion = false;
|
||||
|
||||
for( T token = NextTok(); token != T_EOF; token = NextTok() )
|
||||
|
@ -91,15 +89,6 @@ void DRC_RULES_PARSER::Parse( std::vector<DRC_SELECTOR*>& aSelectors,
|
|||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_selector:
|
||||
{
|
||||
wxString ruleName;
|
||||
|
||||
aSelectors.push_back( parseDRC_SELECTOR( &ruleName ) );
|
||||
selectorRules.emplace_back( aSelectors.back(), ruleName );
|
||||
}
|
||||
break;
|
||||
|
||||
case T_rule:
|
||||
aRules.push_back( parseDRC_RULE() );
|
||||
break;
|
||||
|
@ -108,118 +97,6 @@ void DRC_RULES_PARSER::Parse( std::vector<DRC_SELECTOR*>& aSelectors,
|
|||
Expecting( "selector or rule" );
|
||||
}
|
||||
}
|
||||
|
||||
// Hook up the selectors to their rules
|
||||
std::map<wxString, DRC_RULE*> ruleMap;
|
||||
|
||||
for( DRC_RULE* rule : aRules )
|
||||
ruleMap[ rule->m_Name ] = rule;
|
||||
|
||||
for( const std::pair<DRC_SELECTOR*, wxString>& entry : selectorRules )
|
||||
{
|
||||
if( ruleMap.count( entry.second ) )
|
||||
{
|
||||
entry.first->m_Rule = ruleMap[ entry.second ];
|
||||
}
|
||||
else
|
||||
{
|
||||
wxString errText = wxString::Format( _( "Rule \"%s\" not found." ), entry.second );
|
||||
THROW_PARSE_ERROR( errText, CurSource(), "", 0, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DRC_SELECTOR* DRC_RULES_PARSER::parseDRC_SELECTOR( wxString* aRuleName )
|
||||
{
|
||||
NETCLASSES& netclasses = m_board->GetDesignSettings().GetNetClasses();
|
||||
DRC_SELECTOR* selector = new DRC_SELECTOR();
|
||||
T token;
|
||||
|
||||
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
|
||||
{
|
||||
if( token != T_LEFT )
|
||||
Expecting( T_LEFT );
|
||||
|
||||
token = NextTok();
|
||||
|
||||
switch( token )
|
||||
{
|
||||
case T_match_netclass:
|
||||
{
|
||||
NeedSYMBOL();
|
||||
NETCLASSPTR netclass = netclasses.Find( FromUTF8() );
|
||||
|
||||
if( netclass )
|
||||
{
|
||||
selector->m_MatchNetclasses.push_back( std::move( netclass ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Interesting situation here: if we don't inform the user they may have a typo
|
||||
// and can't figure out why their rules don't work.
|
||||
// If we do tell them then it gets really noisy if they're using a single rule
|
||||
// file for a class of board.
|
||||
}
|
||||
|
||||
NeedRIGHT();
|
||||
}
|
||||
break;
|
||||
|
||||
case T_match_type:
|
||||
switch( NextTok() )
|
||||
{
|
||||
case T_track: selector->m_MatchTypes.push_back( PCB_TRACE_T ); break;
|
||||
case T_via: selector->m_MatchTypes.push_back( PCB_LOCATE_STDVIA_T ); break;
|
||||
case T_micro_via: selector->m_MatchTypes.push_back( PCB_LOCATE_UVIA_T ); break;
|
||||
case T_buried_via: selector->m_MatchTypes.push_back( PCB_LOCATE_BBVIA_T ); break;
|
||||
case T_pad: selector->m_MatchTypes.push_back( PCB_PAD_T ); break;
|
||||
case T_zone: selector->m_MatchTypes.push_back( PCB_ZONE_AREA_T ); break;
|
||||
case T_text: selector->m_MatchTypes.push_back( PCB_LOCATE_TEXT_T ); break;
|
||||
case T_graphic: selector->m_MatchTypes.push_back( PCB_LOCATE_GRAPHIC_T ); break;
|
||||
case T_hole: selector->m_MatchTypes.push_back( PCB_LOCATE_HOLE_T ); break;
|
||||
case T_npth: selector->m_MatchTypes.push_back( PCB_LOCATE_NPTH_T ); break;
|
||||
case T_pth: selector->m_MatchTypes.push_back( PCB_LOCATE_PTH_T ); break;
|
||||
case T_board_edge: selector->m_MatchTypes.push_back( PCB_LOCATE_BOARD_EDGE_T ); break;
|
||||
default: Expecting( "track, via, micro_via, buried_via, pad, zone, text, "
|
||||
"graphic, hole, npth, pth, or board_edge" );
|
||||
}
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_match_layer:
|
||||
NeedSYMBOL();
|
||||
|
||||
if( m_layerMap.count( curText ) )
|
||||
{
|
||||
selector->m_MatchLayers.push_back( m_layerMap[ curText ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
wxString errText = wxString::Format( _( "Layer \"%s\" not found." ),
|
||||
wxString( curText ) );
|
||||
THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
|
||||
}
|
||||
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
case T_match_area:
|
||||
// TODO
|
||||
break;
|
||||
|
||||
case T_rule:
|
||||
NeedSYMBOL();
|
||||
*aRuleName = FromUTF8();
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
default:
|
||||
Expecting( "match_netclass, match_type, match_layer, match_area, or rule" );
|
||||
}
|
||||
}
|
||||
|
||||
return selector;
|
||||
}
|
||||
|
||||
|
||||
|
@ -269,7 +146,15 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
|
|||
|
||||
case T_condition:
|
||||
NeedSYMBOL();
|
||||
rule->m_Condition = FromUTF8();
|
||||
rule->m_Condition.m_Expression = FromUTF8();
|
||||
|
||||
if( !rule->m_Condition.Compile() )
|
||||
{
|
||||
LIBEVAL::ERROR_STATUS error = rule->m_Condition.GetCompilationError();
|
||||
THROW_PARSE_ERROR( error.message, CurSource(), CurLine(), CurLineNumber(),
|
||||
CurOffset() + error.srcPos );
|
||||
}
|
||||
|
||||
NeedRIGHT();
|
||||
break;
|
||||
|
||||
|
|
|
@ -43,13 +43,11 @@ public:
|
|||
DRC_RULES_PARSER( BOARD* aBoard, const wxString& aSource, const wxString& aSourceDescr );
|
||||
DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxString& aFilename );
|
||||
|
||||
void Parse( std::vector<DRC_SELECTOR*>& aSelectors, std::vector<DRC_RULE*>& aRules );
|
||||
void Parse( std::vector<DRC_RULE*>& aRules );
|
||||
|
||||
private:
|
||||
void initLayerMap();
|
||||
|
||||
DRC_SELECTOR* parseDRC_SELECTOR( wxString* aRuleName );
|
||||
|
||||
DRC_RULE* parseDRC_RULE();
|
||||
|
||||
void parseConstraint( DRC_RULE* aRule );
|
||||
|
|
|
@ -653,7 +653,7 @@ void PCB_EDIT_FRAME::ShowBoardSetupDialog( const wxString& aInitialPage, const w
|
|||
|
||||
if( dlg.ShowQuasiModal() == wxID_OK )
|
||||
{
|
||||
Prj().GetProjectFile().NetSettings().ResolveNetClassAssignments();
|
||||
Prj().GetProjectFile().NetSettings().ResolveNetClassAssignments( true );
|
||||
|
||||
GetBoard()->SynchronizeNetsAndNetClasses();
|
||||
GetBoard()->GetDesignSettings().SetCurrentNetClass( NETCLASS::Default );
|
||||
|
|
|
@ -23,92 +23,94 @@
|
|||
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include "class_board.h"
|
||||
#include "pcb_expr_evaluator.h"
|
||||
|
||||
class PCB_EXPR_BUILTIN_FUNCTIONS
|
||||
{
|
||||
public:
|
||||
public:
|
||||
|
||||
using FPTR = LIBEVAL::UCODE::FUNC_PTR;
|
||||
using FPTR = LIBEVAL::UCODE::FUNC_PTR;
|
||||
|
||||
PCB_EXPR_BUILTIN_FUNCTIONS();
|
||||
PCB_EXPR_BUILTIN_FUNCTIONS();
|
||||
|
||||
static PCB_EXPR_BUILTIN_FUNCTIONS& Instance()
|
||||
static PCB_EXPR_BUILTIN_FUNCTIONS& Instance()
|
||||
{
|
||||
static PCB_EXPR_BUILTIN_FUNCTIONS self;
|
||||
return self;
|
||||
}
|
||||
|
||||
std::string tolower( const std::string& str ) const
|
||||
{
|
||||
std::string rv;
|
||||
std::transform( str.begin(), str.end(), rv.begin(), ::tolower );
|
||||
return rv;
|
||||
}
|
||||
|
||||
FPTR Get( const std::string &name ) const
|
||||
{
|
||||
auto it = m_funcs.find( name );
|
||||
|
||||
if( it == m_funcs.end() )
|
||||
return nullptr;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, FPTR> m_funcs;
|
||||
|
||||
static void onLayer( LIBEVAL::UCODE* aUcode, LIBEVAL::UCODE::CONTEXT* aCtx, void *self )
|
||||
{
|
||||
LIBEVAL::VALUE* arg = aCtx->Pop();
|
||||
PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
|
||||
PCB_LAYER_ID layer = ENUM_MAP<PCB_LAYER_ID>::Instance().ToEnum( arg->AsString() );
|
||||
BOARD_ITEM* item = vref->GetObject( aUcode );
|
||||
LIBEVAL::VALUE* rv = aCtx->AllocValue();
|
||||
|
||||
rv->Set( item->IsOnLayer( layer ) ? 1.0 : 0.0 );
|
||||
aCtx->Push( rv );
|
||||
}
|
||||
|
||||
static void isPlated( LIBEVAL::UCODE* aUcode, LIBEVAL::UCODE::CONTEXT* aCtx, void *self )
|
||||
{
|
||||
PCB_EXPR_VAR_REF* vref = static_cast<PCB_EXPR_VAR_REF*>( self );
|
||||
BOARD_ITEM* item = vref->GetObject( aUcode );
|
||||
bool result = false;
|
||||
|
||||
if( item->Type() == PCB_PAD_T )
|
||||
{
|
||||
static PCB_EXPR_BUILTIN_FUNCTIONS self;
|
||||
return self;
|
||||
D_PAD* pad = static_cast<D_PAD*>( item );
|
||||
result = pad->GetAttribute() == PAD_ATTRIB_STANDARD;
|
||||
}
|
||||
|
||||
std::string tolower( const std::string str ) const
|
||||
{
|
||||
std::string rv;
|
||||
std::transform(str.begin(),
|
||||
str.end(),
|
||||
rv.begin(),
|
||||
::tolower);
|
||||
return rv;
|
||||
}
|
||||
|
||||
FPTR Get( const std::string &name ) const
|
||||
{
|
||||
auto it = m_funcs.find( name );
|
||||
|
||||
if( it == m_funcs.end() )
|
||||
return nullptr;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::map<std::string, FPTR> m_funcs;
|
||||
|
||||
static void onLayer( LIBEVAL::UCODE* aUcode, LIBEVAL::UCODE::CONTEXT* aCtx, void *self )
|
||||
{
|
||||
auto arg = aCtx->Pop();
|
||||
auto vref = static_cast<PCB_EXPR_VAR_REF*>( self );
|
||||
auto conv = ENUM_MAP<PCB_LAYER_ID>::Instance();
|
||||
bool value = vref->GetObject(aUcode)->IsOnLayer( conv.ToEnum( arg->AsString() ) );
|
||||
auto rv = aCtx->AllocValue();
|
||||
rv->Set( value ? 1.0 : 0.0 );
|
||||
aCtx->Push( rv );
|
||||
}
|
||||
|
||||
static void isPlated( LIBEVAL::UCODE* aUcode, LIBEVAL::UCODE::CONTEXT* aCtx, void *self )
|
||||
{
|
||||
auto vref = static_cast<PCB_EXPR_VAR_REF*>( self );
|
||||
auto item = vref->GetObject(aUcode);
|
||||
bool result = false;
|
||||
if( item->Type() == PCB_PAD_T )
|
||||
{
|
||||
auto pad = static_cast<D_PAD*>( item );
|
||||
result = pad->GetAttribute() == PAD_ATTRIB_STANDARD;
|
||||
}
|
||||
auto rv = aCtx->AllocValue();
|
||||
rv->Set( result ? 1.0 : 0.0 );
|
||||
aCtx->Push( rv );
|
||||
}
|
||||
LIBEVAL::VALUE* rv = aCtx->AllocValue();
|
||||
rv->Set( result ? 1.0 : 0.0 );
|
||||
aCtx->Push( rv );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
PCB_EXPR_BUILTIN_FUNCTIONS::PCB_EXPR_BUILTIN_FUNCTIONS()
|
||||
{
|
||||
m_funcs[ "onlayer" ] = onLayer;
|
||||
m_funcs[ "isplated" ] = isPlated;
|
||||
}
|
||||
|
||||
|
||||
BOARD_ITEM* PCB_EXPR_VAR_REF::GetObject( LIBEVAL::UCODE* aUcode ) const
|
||||
{
|
||||
auto ucode = static_cast<const PCB_EXPR_UCODE*>( aUcode );
|
||||
auto item = ucode->GetItem( m_itemIndex );
|
||||
const PCB_EXPR_UCODE* ucode = static_cast<const PCB_EXPR_UCODE*>( aUcode );
|
||||
BOARD_ITEM* item = ucode->GetItem( m_itemIndex );
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode )
|
||||
{
|
||||
auto item = GetObject( aUcode );
|
||||
auto it = m_matchingTypes.find( TYPE_HASH( *item ) );
|
||||
BOARD_ITEM* item = const_cast<BOARD_ITEM*>( GetObject( aUcode ) );
|
||||
auto it = m_matchingTypes.find( TYPE_HASH( *item ) );
|
||||
|
||||
if( it == m_matchingTypes.end() )
|
||||
{
|
||||
|
@ -128,7 +130,9 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode )
|
|||
{
|
||||
//printf("item %p Get string '%s'\n", item, (const char*) it->second->Name().c_str() );
|
||||
str = item->Get<wxString>( it->second );
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& any = item->Get( it->second );
|
||||
any.GetAs<wxString>( &str );
|
||||
//printf("item %p get enum: '%s'\n", item , (const char*) str.c_str() );
|
||||
|
@ -138,26 +142,42 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode )
|
|||
}
|
||||
}
|
||||
|
||||
LIBEVAL::UCODE::FUNC_PTR PCB_EXPR_UCODE::createFuncCall( LIBEVAL::COMPILER* aCompiler, const std::string& name )
|
||||
|
||||
LIBEVAL::UCODE::FUNC_PTR PCB_EXPR_UCODE::createFuncCall( LIBEVAL::COMPILER* aCompiler,
|
||||
const std::string& name )
|
||||
{
|
||||
auto registry = PCB_EXPR_BUILTIN_FUNCTIONS::Instance();
|
||||
auto f = registry.Get( name );
|
||||
PCB_EXPR_BUILTIN_FUNCTIONS& registry = PCB_EXPR_BUILTIN_FUNCTIONS::Instance();
|
||||
|
||||
auto f = registry.Get( boost::to_lower_copy( name ) );
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler,
|
||||
const std::string& var, const std::string& field )
|
||||
const std::string& var, const std::string& field )
|
||||
{
|
||||
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
|
||||
PCB_EXPR_VAR_REF* vref = nullptr;
|
||||
|
||||
auto classes = propMgr.GetAllClasses();
|
||||
auto vref = new PCB_EXPR_VAR_REF( var == "A" ? 0 : 1 );
|
||||
if( var == "A" )
|
||||
{
|
||||
vref = new PCB_EXPR_VAR_REF( 0 );
|
||||
}
|
||||
else if( var == "B" )
|
||||
{
|
||||
vref = new PCB_EXPR_VAR_REF( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
aCompiler->ReportError( "var" );
|
||||
return vref;
|
||||
}
|
||||
|
||||
if( field.empty() ) // return reference to base object
|
||||
return vref;
|
||||
|
||||
for( auto cls : classes )
|
||||
for( const PROPERTY_MANAGER::CLASS_INFO& cls : propMgr.GetAllClasses() )
|
||||
{
|
||||
if( propMgr.IsOfType( cls.type, TYPE_HASH( BOARD_ITEM ) ) )
|
||||
{
|
||||
|
@ -167,10 +187,15 @@ LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler,
|
|||
{
|
||||
//printf("Field '%s' class %s ptr %p haschoices %d typeid %s\n", field.c_str(), (const char *) cls.name.c_str(), prop, !!prop->HasChoices(), typeid(*prop).name() );
|
||||
vref->AddAllowedClass( cls.type, prop );
|
||||
|
||||
if( prop->TypeHash() == TYPE_HASH( int ) )
|
||||
{
|
||||
vref->SetType( LIBEVAL::VT_NUMERIC );
|
||||
}
|
||||
else if( prop->TypeHash() == TYPE_HASH( wxString ) )
|
||||
{
|
||||
vref->SetType( LIBEVAL::VT_STRING );
|
||||
}
|
||||
else if ( prop->HasChoices() )
|
||||
{ // it's an enum, we treat it as string
|
||||
vref->SetType( LIBEVAL::VT_STRING );
|
||||
|
@ -186,6 +211,9 @@ LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler,
|
|||
}
|
||||
}
|
||||
|
||||
if( vref->GetType() == LIBEVAL::VT_UNDEFINED )
|
||||
aCompiler->ReportError( "field" );
|
||||
|
||||
return vref;
|
||||
}
|
||||
|
||||
|
@ -204,19 +232,16 @@ public:
|
|||
return pcbUnits;
|
||||
}
|
||||
|
||||
virtual double Convert( const std::string aString, int unitId ) const override
|
||||
virtual double Convert( const std::string& aString, int unitId ) const override
|
||||
{
|
||||
double v = atof( aString.c_str() );
|
||||
|
||||
switch( unitId )
|
||||
{
|
||||
case 0:
|
||||
return Mils2iu( v );
|
||||
case 1:
|
||||
return Millimeter2iu( v );
|
||||
case 2:
|
||||
return Mils2iu( v * 1000.0 );
|
||||
default:
|
||||
return v;
|
||||
case 0: return Mils2iu( v );
|
||||
case 1: return Millimeter2iu( v );
|
||||
case 2: return Mils2iu( v * 1000.0 );
|
||||
default: return v;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -66,6 +66,7 @@ class PCB_EXPR_VAR_REF : public LIBEVAL::VAR_REF
|
|||
public:
|
||||
PCB_EXPR_VAR_REF( int aItemIndex ) :
|
||||
m_itemIndex( aItemIndex ),
|
||||
m_type( LIBEVAL::VT_UNDEFINED ),
|
||||
m_isEnum( false )
|
||||
{
|
||||
//printf("*** createVarRef %p %d\n", this, aItemIndex );
|
||||
|
@ -84,7 +85,7 @@ public:
|
|||
m_matchingTypes[type_hash] = prop;
|
||||
}
|
||||
|
||||
virtual LIBEVAL::VAR_TYPE_T GetType( LIBEVAL::UCODE* aUcode ) override
|
||||
virtual LIBEVAL::VAR_TYPE_T GetType() override
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
@ -98,7 +99,7 @@ private:
|
|||
std::unordered_map<TYPE_ID, PROPERTY_BASE*> m_matchingTypes;
|
||||
int m_itemIndex;
|
||||
LIBEVAL::VAR_TYPE_T m_type;
|
||||
bool m_isEnum;
|
||||
bool m_isEnum;
|
||||
};
|
||||
|
||||
|
||||
|
@ -116,10 +117,7 @@ public:
|
|||
~PCB_EXPR_EVALUATOR();
|
||||
|
||||
bool Evaluate( const wxString& aExpr );
|
||||
int Result() const
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
int Result() const { return m_result; }
|
||||
wxString GetErrorString();
|
||||
|
||||
private:
|
||||
|
|
|
@ -186,7 +186,6 @@ bool DRC::LoadRules()
|
|||
|
||||
if( rulesFile.FileExists() )
|
||||
{
|
||||
m_ruleSelectors.clear();
|
||||
m_rules.clear();
|
||||
|
||||
FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) );
|
||||
|
@ -196,12 +195,11 @@ bool DRC::LoadRules()
|
|||
try
|
||||
{
|
||||
DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath );
|
||||
parser.Parse( m_ruleSelectors, m_rules );
|
||||
parser.Parse( m_rules );
|
||||
}
|
||||
catch( PARSE_ERROR& pe )
|
||||
{
|
||||
// Don't leave possibly malformed stuff around for us to trip over
|
||||
m_ruleSelectors.clear();
|
||||
m_rules.clear();
|
||||
|
||||
wxSafeYield( m_editFrame );
|
||||
|
|
|
@ -47,23 +47,26 @@ test::DRC_RULE_CONDITION::DRC_RULE_CONDITION()
|
|||
m_ucode = nullptr;
|
||||
}
|
||||
|
||||
|
||||
test::DRC_RULE_CONDITION::~DRC_RULE_CONDITION()
|
||||
{
|
||||
if( m_ucode )
|
||||
delete m_ucode;
|
||||
delete m_ucode;
|
||||
}
|
||||
|
||||
bool test::DRC_RULE_CONDITION::EvaluateFor( BOARD_ITEM* aItemA, BOARD_ITEM* aItemB )
|
||||
|
||||
bool test::DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB )
|
||||
{
|
||||
m_ucode->SetItems( aItemA, aItemB );
|
||||
m_ucode->SetItems( const_cast<BOARD_ITEM*>( aItemA ), const_cast<BOARD_ITEM*>( aItemB ) );
|
||||
|
||||
// fixme: handle error conditions
|
||||
return m_ucode->Run()->AsDouble() != 0.0;
|
||||
}
|
||||
|
||||
|
||||
bool test::DRC_RULE_CONDITION::Compile()
|
||||
{
|
||||
PCB_EXPR_COMPILER compiler;
|
||||
|
||||
if (!m_ucode)
|
||||
m_ucode = new PCB_EXPR_UCODE;
|
||||
|
||||
|
@ -74,11 +77,12 @@ bool test::DRC_RULE_CONDITION::Compile()
|
|||
|
||||
m_compileError = compiler.GetErrorStatus();
|
||||
|
||||
printf("Fail: %s", m_compileError.Format().c_str() );
|
||||
printf( "Fail: %s", m_compileError.Format().c_str() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
LIBEVAL::ERROR_STATUS test::DRC_RULE_CONDITION::GetCompilationError()
|
||||
{
|
||||
return m_compileError;
|
||||
|
|
|
@ -130,7 +130,7 @@ public:
|
|||
DRC_RULE_CONDITION();
|
||||
~DRC_RULE_CONDITION();
|
||||
|
||||
bool EvaluateFor( BOARD_ITEM* aItemA, BOARD_ITEM* aItemB );
|
||||
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB );
|
||||
bool Compile();
|
||||
LIBEVAL::ERROR_STATUS GetCompilationError();
|
||||
|
||||
|
@ -140,7 +140,7 @@ public:
|
|||
|
||||
private:
|
||||
LIBEVAL::ERROR_STATUS m_compileError;
|
||||
PCB_EXPR_UCODE* m_ucode;
|
||||
PCB_EXPR_UCODE* m_ucode;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -118,20 +118,20 @@ int main( int argc, char *argv[] )
|
|||
trackA.SetWidth( Mils2iu( 10 ));
|
||||
trackB.SetWidth( Mils2iu( 20 ));
|
||||
|
||||
printf("TrkA %p netclass '%s'\n", &trackA, (const char*) trackA.GetNetClassName().c_str() );
|
||||
printf("TrkB %p netclass '%s'\n", &trackB, (const char*) trackB.GetNetClassName().c_str() );
|
||||
printf( "TrkA %p netclass '%s'\n", &trackA, (const char*) trackA.GetNetClassName().c_str() );
|
||||
printf( "TrkB %p netclass '%s'\n", &trackB, (const char*) trackB.GetNetClassName().c_str() );
|
||||
|
||||
// testEvalExpr( "A.onlayer(\"F.Cu\") || A.onlayer(\"B.Cu\")", VAL(1.0), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.type == \"Pad\" && B.type == \"Pad\" && (A.onLayer(\"F.Cu\"))",VAL(0.0), false, &trackA, &trackB );
|
||||
// testEvalExpr( "A.onlayer('F.Cu') || A.onlayer('B.Cu')", VAL( 1.0 ), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.type == 'Pad' && B.type == 'Pad' && (A.onLayer('F.Cu'))", VAL( 0.0 ), false, &trackA, &trackB );
|
||||
return 0;
|
||||
testEvalExpr( "A.Width > B.Width", VAL(0.0), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.Width + B.Width", VAL(Mils2iu(10) + Mils2iu(20)), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.Width > B.Width", VAL( 0.0 ), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.Width + B.Width", VAL( Mils2iu(10) + Mils2iu(20) ), false, &trackA, &trackB );
|
||||
|
||||
testEvalExpr( "A.Netclass", VAL( (const char*) trackA.GetNetClassName().c_str() ), false, &trackA, &trackB );
|
||||
testEvalExpr( "(A.Netclass == \"HV\") && (B.netclass == \"otherClass\") && (B.netclass != \"F.Cu\")", VAL( 1.0 ), false, &trackA, &trackB );
|
||||
testEvalExpr( "(A.Netclass == 'HV') && (B.netclass == 'otherClass') && (B.netclass != 'F.Cu')", VAL( 1.0 ), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.Netclass + 1.0", VAL( 1.0 ), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.type == \"Track\" && B.type == \"Track\" && A.layer == \"F.Cu\"", VAL(0.0), false, &trackA, &trackB );
|
||||
testEvalExpr( "(A.type == \"Track\") && (B.type == \"Track\") && (A.layer == \"F.Cu\")", VAL(0.0), false, &trackA, &trackB );
|
||||
testEvalExpr( "A.type == 'Track' && B.type == 'Track' && A.layer == 'F.Cu'", VAL( 0.0 ), false, &trackA, &trackB );
|
||||
testEvalExpr( "(A.type == 'Track') && (B.type == 'Track') && (A.layer == 'F.Cu')", VAL( 0.0 ), false, &trackA, &trackB );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue