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:
Jeff Young 2020-07-19 22:22:49 +01:00
parent 6d8fb94d86
commit 095937563b
33 changed files with 708 additions and 742 deletions

View File

@ -971,114 +971,114 @@ static YYACTIONTYPE yy_reduce(
break; break;
case 1: /* expr ::= G_VALUE */ case 1: /* expr ::= G_VALUE */
#line 58 "grammar.lemon" #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" #line 976 "grammar.c"
yymsp[0].minor.yy0 = yylhsminor.yy0; yymsp[0].minor.yy0 = yylhsminor.yy0;
break; break;
case 2: /* expr ::= G_VALUE G_UNIT */ case 2: /* expr ::= G_VALUE G_UNIT */
#line 59 "grammar.lemon" #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" #line 982 "grammar.c"
yymsp[-1].minor.yy0 = yylhsminor.yy0; yymsp[-1].minor.yy0 = yylhsminor.yy0;
break; break;
case 3: /* expr ::= G_STRING */ case 3: /* expr ::= G_STRING */
#line 60 "grammar.lemon" #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" #line 988 "grammar.c"
yymsp[0].minor.yy0 = yylhsminor.yy0; yymsp[0].minor.yy0 = yylhsminor.yy0;
break; break;
case 4: /* expr ::= G_IDENTIFIER */ case 4: /* expr ::= G_IDENTIFIER */
#line 61 "grammar.lemon" #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" #line 994 "grammar.c"
yymsp[0].minor.yy0 = yylhsminor.yy0; yymsp[0].minor.yy0 = yylhsminor.yy0;
break; break;
case 5: /* expr ::= expr G_LESS_THAN expr */ case 5: /* expr ::= expr G_LESS_THAN expr */
#line 62 "grammar.lemon" #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" #line 1000 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 6: /* expr ::= expr G_GREATER_THAN expr */ case 6: /* expr ::= expr G_GREATER_THAN expr */
#line 63 "grammar.lemon" #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" #line 1006 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 7: /* expr ::= expr G_LESS_EQUAL_THAN expr */ case 7: /* expr ::= expr G_LESS_EQUAL_THAN expr */
#line 64 "grammar.lemon" #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" #line 1012 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 8: /* expr ::= expr G_GREATER_EQUAL_THAN expr */ case 8: /* expr ::= expr G_GREATER_EQUAL_THAN expr */
#line 65 "grammar.lemon" #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" #line 1018 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 9: /* expr ::= expr G_NOT_EQUAL expr */ case 9: /* expr ::= expr G_NOT_EQUAL expr */
#line 66 "grammar.lemon" #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" #line 1024 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 10: /* expr ::= expr G_BOOL_AND expr */ case 10: /* expr ::= expr G_BOOL_AND expr */
#line 67 "grammar.lemon" #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" #line 1030 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 11: /* expr ::= expr G_BOOL_OR expr */ case 11: /* expr ::= expr G_BOOL_OR expr */
#line 68 "grammar.lemon" #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" #line 1036 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 12: /* expr ::= expr G_PLUS expr */ case 12: /* expr ::= expr G_PLUS expr */
#line 69 "grammar.lemon" #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" #line 1042 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 13: /* expr ::= expr G_MINUS expr */ case 13: /* expr ::= expr G_MINUS expr */
#line 70 "grammar.lemon" #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" #line 1048 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 14: /* expr ::= expr G_MULT expr */ case 14: /* expr ::= expr G_MULT expr */
#line 71 "grammar.lemon" #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" #line 1054 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 15: /* expr ::= expr G_DIVIDE expr */ case 15: /* expr ::= expr G_DIVIDE expr */
#line 72 "grammar.lemon" #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" #line 1060 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 16: /* expr ::= expr G_EQUAL expr */ case 16: /* expr ::= expr G_EQUAL expr */
#line 73 "grammar.lemon" #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" #line 1066 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 17: /* expr ::= expr G_STRUCT_REF expr */ case 17: /* expr ::= expr G_STRUCT_REF expr */
#line 75 "grammar.lemon" #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" #line 1072 "grammar.c"
yymsp[-2].minor.yy0 = yylhsminor.yy0; yymsp[-2].minor.yy0 = yylhsminor.yy0;
break; break;
case 18: /* expr ::= G_PARENL expr G_PARENR */ case 18: /* expr ::= G_PARENL expr G_PARENR */
#line 77 "grammar.lemon" #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" #line 1078 "grammar.c"
break; break;
case 19: /* expr ::= G_IDENTIFIER G_PARENL expr G_PARENR */ case 19: /* expr ::= G_IDENTIFIER G_PARENL expr G_PARENR */
#line 78 "grammar.lemon" #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" #line 1083 "grammar.c"
yymsp[-3].minor.yy0 = yylhsminor.yy0; yymsp[-3].minor.yy0 = yylhsminor.yy0;
break; break;

View File

@ -53,27 +53,27 @@ in ::= in stmt.
/* A statement can be empty, an expr or an expr followed by ';' */ /* A statement can be empty, an expr or an expr followed by ';' */
stmt ::= G_ENDS. stmt ::= G_ENDS.
stmt ::= expr(A) G_ENDS. { pEval->setRoot(A); } stmt ::= expr(A) G_ENDS. { pEval->setRoot(A); }
//stmt ::= expr G_SEMCOL. { pEval->setRoot(NULL) } //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). { 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; } 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; } 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; } 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; } 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; } 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; } 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; } 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; } 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; } 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; } 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; } 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; } 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; } 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; } 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; } 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_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(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_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(); }

View File

@ -18,6 +18,7 @@
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <memory>
#include <set> #include <set>
#include <vector> #include <vector>
@ -67,18 +68,20 @@ static const std::string formatOpName( int op )
{ {
int op; int op;
std::string mnemonic; 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_SUB, "SUB" }, { TR_OP_LESS, "LESS" }, { TR_OP_GREATER, "GREATER" },
{ TR_OP_LESS_EQUAL, "LESS_EQUAL" }, { TR_OP_GREATER_EQUAL, "GREATER_EQUAL" }, { 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_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++ ) for( int i = 0; simpleOps[i].op >= 0; i++ )
{ {
if( simpleOps[i].op == op ) if( simpleOps[i].op == op )
{
return simpleOps[i].mnemonic; return simpleOps[i].mnemonic;
}
} }
return "???"; return "???";
@ -87,32 +90,40 @@ static const std::string formatOpName( int op )
std::string UOP::Format() const std::string UOP::Format() const
{ {
char str[1024]; char str[LIBEVAL_MAX_LITERAL_LENGTH];
switch( m_op ) switch( m_op )
{ {
case TR_UOP_PUSH_VAR: case TR_UOP_PUSH_VAR:
sprintf( str, "PUSH VAR [%p]", m_arg ); snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH VAR [%p]", m_arg );
break; break;
case TR_UOP_PUSH_VALUE: case TR_UOP_PUSH_VALUE:
{ {
auto val = reinterpret_cast<VALUE*>( m_arg ); VALUE* val = reinterpret_cast<VALUE*>( m_arg );
if( val->GetType() == VT_NUMERIC )
sprintf( str, "PUSH NUM [%.10f]", val->AsDouble() ); 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 else
sprintf( str, "PUSH STR [%s]", val->AsString().c_str() ); snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH STR [%s]", val->AsString().c_str() );
break;
} }
break;
case TR_OP_METHOD_CALL: case TR_OP_METHOD_CALL:
sprintf(str, "MCALL" ); snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "MCALL" );
break; break;
case TR_OP_FUNC_CALL: case TR_OP_FUNC_CALL:
sprintf(str, "FCALL" ); snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "FCALL" );
break; break;
default: 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; break;
} }
return str; return str;
} }
@ -140,7 +151,7 @@ std::string TOKENIZER::GetChars( std::function<bool( int )> cond ) const
return rv; 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; int remaining = m_str.length() - m_pos;
if( remaining < (int) match.length() ) if( remaining < (int) match.length() )
@ -158,11 +169,10 @@ COMPILER::COMPILER()
{ {
m_errorStatus.pendingError = false; m_errorStatus.pendingError = false;
m_localeDecimalSeparator = '.'; m_localeDecimalSeparator = '.';
m_parseFinished = false; m_sourcePos = 0;
m_unitResolver.reset( new UNIT_RESOLVER ); m_parseFinished = false;
m_unitResolver = std::make_unique<UNIT_RESOLVER>();
m_parser = LIBEVAL::ParseAlloc( malloc ); m_parser = LIBEVAL::ParseAlloc( malloc );
m_parseError = false;
m_parseErrorPos = 0;
m_tree = nullptr; m_tree = nullptr;
} }
@ -207,7 +217,7 @@ bool COMPILER::Compile( const std::string& aString, UCODE* aCode )
newString( aString ); newString( aString );
m_errorStatus.pendingError = false; m_errorStatus.pendingError = false;
m_tree = nullptr; m_tree = nullptr;
m_parseFinished = false; m_parseFinished = false;
T_TOKEN tok; T_TOKEN tok;
@ -221,6 +231,8 @@ bool COMPILER::Compile( const std::string& aString, UCODE* aCode )
do do
{ {
m_sourcePos = m_tokenizer.GetPos();
tok = getToken(); tok = getToken();
libeval_dbg(10, "parse: tok %d\n", tok.token ); libeval_dbg(10, "parse: tok %d\n", tok.token );
Parse( m_parser, tok.token, tok.value, this ); 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 ) if( m_errorStatus.pendingError )
{ {
m_errorStatus.stage = ERROR_STATUS::CST_PARSE; m_errorStatus.stage = ERROR_STATUS::CST_PARSE;
m_errorStatus.failingPosition = m_tokenizer.GetPos(); m_errorStatus.message.Printf( _( "Unrecognized token '%s'" ), tok.value.value.str );
m_errorStatus.failingObject = tok.value.value.str; m_errorStatus.srcPos = m_tokenizer.GetPos();
m_errorStatus.message = "Parse error";
return false; return false;
} }
@ -261,7 +272,6 @@ COMPILER::T_TOKEN COMPILER::getToken()
bool done = false; bool done = false;
do do
{ {
switch( m_lexerState ) switch( m_lexerState )
{ {
case LS_DEFAULT: case LS_DEFAULT:
@ -280,7 +290,7 @@ COMPILER::T_TOKEN COMPILER::getToken()
bool COMPILER::lexString( COMPILER::T_TOKEN& aToken ) 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() ); //printf("STR LIT '%s'\n", (const char *)str.c_str() );
aToken.token = G_STRING; aToken.token = G_STRING;
@ -310,6 +320,7 @@ int COMPILER::resolveUnits()
return -1; return -1;
} }
bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken ) bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken )
{ {
T_TOKEN retval; T_TOKEN retval;
@ -326,38 +337,44 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken )
return true; return true;
} }
auto isDecimalSeparator = [&]( char ch ) -> bool { auto isDecimalSeparator =
return ( ch == m_localeDecimalSeparator || ch == '.' || ch == ',' ); [&]( char ch ) -> bool
}; {
return ( ch == m_localeDecimalSeparator || ch == '.' || ch == ',' );
};
// Lambda: get value as string, store into clToken.token and update current index. // Lambda: get value as string, store into clToken.token and update current index.
auto extractNumber = [&]() { auto extractNumber =
bool haveSeparator = false; [&]()
idx = 0; {
auto ch = m_tokenizer.GetChar(); bool haveSeparator = false;
idx = 0;
int ch = m_tokenizer.GetChar();
do do
{ {
if( isDecimalSeparator( ch ) && haveSeparator ) if( isDecimalSeparator( ch ) && haveSeparator )
break; break;
current.append( 1, ch ); current.append( 1, ch );
if( isDecimalSeparator( ch ) ) if( isDecimalSeparator( ch ) )
haveSeparator = true; haveSeparator = true;
m_tokenizer.NextChar(); m_tokenizer.NextChar();
ch = m_tokenizer.GetChar(); ch = m_tokenizer.GetChar();
} while( isdigit( ch ) || isDecimalSeparator( ch ) ); } while( isdigit( ch ) || isDecimalSeparator( ch ) );
// Ensure that the systems decimal separator is used // Ensure that the systems decimal separator is used
for( int i = current.length(); i; i-- ) for( int i = current.length(); i; i-- )
if( isDecimalSeparator( current[i - 1] ) ) {
current[i - 1] = m_localeDecimalSeparator; 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; int ch;
@ -398,7 +415,7 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken )
retval.token = G_UNIT; retval.token = G_UNIT;
retval.value.value.type = convertFrom; retval.value.value.type = convertFrom;
} }
else if( ch == '\"' ) // string literal else if( ch == '\'' ) // string literal
{ {
//printf( "MATCH STRING LITERAL\n" ); //printf( "MATCH STRING LITERAL\n" );
m_lexerState = LS_STRING; m_lexerState = LS_STRING;
@ -488,9 +505,8 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken )
break; break;
default: default:
m_errorStatus.stage = ERROR_STATUS::CST_PARSE; m_errorStatus.stage = ERROR_STATUS::CST_PARSE;
m_errorStatus.failingPosition = m_tokenizer.GetPos(); m_errorStatus.message.Printf( _( "Unrecognized character '%c'" ), (char) ch );
m_errorStatus.failingObject = ch; m_errorStatus.srcPos = m_tokenizer.GetPos();
m_errorStatus.message = "Syntax error";
break; /* invalid character */ break; /* invalid character */
} }
@ -564,11 +580,10 @@ void dumpNode( std::string& buf, TREE_NODE* tok, int depth = 0 )
ERROR_STATUS COMPILER::GetErrorStatus() ERROR_STATUS COMPILER::GetErrorStatus()
{ {
ERROR_STATUS dummy; return m_errorStatus;
return dummy;
} }
void COMPILER::ReportError( const std::string aErrorMsg ) void COMPILER::ReportError( const std::string& aErrorMsg )
{ {
m_errorStatus.pendingError = true; m_errorStatus.pendingError = true;
m_errorStatus.message = aErrorMsg; m_errorStatus.message = aErrorMsg;
@ -585,9 +600,10 @@ bool COMPILER::generateUCode( UCODE* aCode )
std::vector<TREE_NODE*> stack; std::vector<TREE_NODE*> stack;
std::set<TREE_NODE*> visitedNodes; std::set<TREE_NODE*> visitedNodes;
auto visited = [&]( TREE_NODE* node ) -> bool { auto visited = [&]( TREE_NODE* node ) -> bool
return visitedNodes.find( node ) != visitedNodes.end(); {
}; return visitedNodes.find( node ) != visitedNodes.end();
};
assert( m_tree ); assert( m_tree );
@ -603,7 +619,7 @@ bool COMPILER::generateUCode( UCODE* aCode )
while( !stack.empty() ) while( !stack.empty() )
{ {
auto node = stack.back(); TREE_NODE* node = stack.back();
libeval_dbg( 4, "process node %p [op %d] [stack %lu]\n", libeval_dbg( 4, "process node %p [op %d] [stack %lu]\n",
node, node->op, (unsigned long)stack.size() ); node, node->op, (unsigned long)stack.size() );
@ -623,47 +639,71 @@ bool COMPILER::generateUCode( UCODE* aCode )
{ {
case TR_IDENTIFIER: 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 ) 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; return false;
} }
node->uop = makeUop( TR_UOP_PUSH_VAR, vref ); node->uop = makeUop( TR_UOP_PUSH_VAR, vref );
node->isTerminal = true; node->isTerminal = true;
break; break;
} }
case TR_OP_FUNC_CALL: 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); if( m_errorStatus.pendingError )
auto vref = aCode->createVarRef( this, node->leaf[0]->value.str, ""); {
auto func = aCode->createFuncCall( this, node->leaf[1]->leaf[0]->value.str ); 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.pendingError = true;
m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN; 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; return false;
// fixme: generate a message
} }
// printf("cfc4 test\n");
// func(nullptr, nullptr, nullptr);
visitedNodes.insert( node->leaf[0] ); visitedNodes.insert( node->leaf[0] );
visitedNodes.insert( node->leaf[1]->leaf[0] ); visitedNodes.insert( node->leaf[1]->leaf[0] );
node->uop = makeUop( TR_OP_METHOD_CALL, func, vref ); node->uop = makeUop( TR_OP_METHOD_CALL, func, vref );
node->isTerminal = false; node->isTerminal = false;
}
break; break;
} }
} }
break; break;
}
case TR_NUMBER: case TR_NUMBER:
{ {
@ -711,15 +751,15 @@ bool COMPILER::generateUCode( UCODE* aCode )
} }
visitedNodes.insert( node ); visitedNodes.insert( node );
if(node->uop) if(node->uop)
aCode->AddOp(node->uop); aCode->AddOp(node->uop);
stack.pop_back();
stack.pop_back();
} }
libeval_dbg(2,"DUMp: \n%s\n", aCode->Dump().c_str() ); libeval_dbg(2,"DUMp: \n%s\n", aCode->Dump().c_str() );
return true; return true;
} }
@ -734,8 +774,8 @@ void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode )
auto value = ctx->AllocValue(); auto value = ctx->AllocValue();
value->Set( reinterpret_cast<VAR_REF*>( m_arg )->GetValue( ucode ) ); value->Set( reinterpret_cast<VAR_REF*>( m_arg )->GetValue( ucode ) );
ctx->Push( value ); ctx->Push( value );
break;
} }
break;
case TR_UOP_PUSH_VALUE: case TR_UOP_PUSH_VALUE:
ctx->Push( reinterpret_cast<VALUE*>( m_arg ) ); ctx->Push( reinterpret_cast<VALUE*>( m_arg ) );
@ -745,15 +785,16 @@ void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode )
//printf("CALL METHOD %s\n" ); //printf("CALL METHOD %s\n" );
m_func( ucode, ctx, m_arg ); m_func( ucode, ctx, m_arg );
return; return;
default: default:
break; break;
} }
if( m_op & TR_OP_BINARY_MASK ) if( m_op & TR_OP_BINARY_MASK )
{ {
auto arg2 = ctx->Pop(); LIBEVAL::VALUE* arg2 = ctx->Pop();
auto arg1 = ctx->Pop(); LIBEVAL::VALUE* arg1 = ctx->Pop();
double result; double result;
switch( m_op ) switch( m_op )
{ {
@ -815,30 +856,22 @@ void UOP::Exec( UCODE::CONTEXT* ctx, UCODE* ucode )
} }
} }
VALUE* UCODE::Run() VALUE* UCODE::Run()
{ {
CONTEXT ctx; CONTEXT ctx;
for( const auto op : m_ucode )
for( UOP* op : m_ucode )
op->Exec( &ctx, this ); op->Exec( &ctx, this );
assert( ctx.SP() == 1 ); assert( ctx.SP() == 1 );
return ctx.Pop(); 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 } // namespace LIBEVAL

View File

@ -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(); m_NetClassAssignments.clear();
for( const auto& ii : existing ) for( const auto& ii : baseList )
{ {
m_NetClassAssignments[ ii.first ] = ii.second; m_NetClassAssignments[ ii.first ] = ii.second;

View File

@ -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 PROPERTY_BASE* PROPERTY_MANAGER::GetProperty( TYPE_ID aType, const wxString& aProperty ) const
{ {
wxASSERT_MSG( !m_dirty, "Have not called PROPERTY_MANAGER::Rebuild(), " if( m_dirty )
"property list not up-to-date" ); const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
auto it = m_classes.find( aType ); 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; 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() ) ) if( !aProperty.CmpNoCase( property->Name() ) )
return property; 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 const PROPERTY_LIST& PROPERTY_MANAGER::GetProperties( TYPE_ID aType ) const
{ {
wxASSERT_MSG( !m_dirty, "Have not called PROPERTY_MANAGER::Rebuild(), " if( m_dirty )
"property list not up-to-date" ); const_cast<PROPERTY_MANAGER*>( this )->Rebuild();
static const PROPERTY_LIST empty; static const PROPERTY_LIST empty;
auto it = m_classes.find( aType ); auto it = m_classes.find( aType );
@ -138,7 +138,7 @@ void PROPERTY_MANAGER::InheritsAfter( TYPE_ID aDerived, TYPE_ID aBase )
m_dirty = true; m_dirty = true;
wxASSERT_MSG( derived.m_bases.size() == 1 || derived.m_typeCasts.count( aBase ) == 1, 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() void PROPERTY_MANAGER::Rebuild()
{ {
wxASSERT_MSG( m_dirty, "Excessive Rebuild() call" ); for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
for( auto& classEntry : m_classes )
{
classEntry.second.rebuild(); classEntry.second.rebuild();
}
m_dirty = false; 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 ); 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 // Do not store replaced properties
if( aReplaced.count( std::make_pair( property->OwnerHash(), property->Name() ) ) == 0 ) if( aReplaced.count( std::make_pair( property->OwnerHash(), property->Name() ) ) == 0 )
aResult.push_back( property ); 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 ); base.get().collectPropsRecur( aResult, aReplaced );
} }
std::vector<TYPE_ID> PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aProperty ) std::vector<TYPE_ID> PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aProperty )
{ {
std::vector<TYPE_ID> ids; std::vector<TYPE_ID> ids;
/*
for( auto& cls : m_classes ) for( auto& cls : m_classes )
{ {
CLASS_INFO info; CLASS_INFO info;
@ -226,24 +225,27 @@ std::vector<TYPE_ID> PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aPrope
} }
*/
return ids; return ids;
} }
PROPERTY_MANAGER::CLASSES_INFO PROPERTY_MANAGER::GetAllClasses() PROPERTY_MANAGER::CLASSES_INFO PROPERTY_MANAGER::GetAllClasses()
{ {
CLASSES_INFO rv; CLASSES_INFO rv;
for( auto& cls : m_classes )
for( std::pair<const TYPE_ID, CLASS_DESC>& classEntry : m_classes )
{ {
CLASS_INFO info; CLASS_INFO info;
info.type = cls.first; info.type = classEntry.first;
info.name = m_classNames[cls.first]; info.name = m_classNames[classEntry.first];
for( auto prop : cls.second.m_allProperties ) for( PROPERTY_BASE* prop : classEntry.second.m_allProperties )
info.properties.push_back(prop); info.properties.push_back( prop );
rv.push_back(info); rv.push_back( info );
} }
return rv; return rv;

View File

@ -268,7 +268,7 @@ void SCH_EDIT_FRAME::ShowSchematicSetupDialog( const wxString& aInitialPage )
if( dlg.ShowQuasiModal() == wxID_OK ) if( dlg.ShowQuasiModal() == wxID_OK )
{ {
Prj().GetProjectFile().NetSettings().ResolveNetClassAssignments(); Prj().GetProjectFile().NetSettings().ResolveNetClassAssignments( true );
SaveProjectSettings(); SaveProjectSettings();
Kiway().CommonSettingsChanged( false, true ); Kiway().CommonSettingsChanged( false, true );

View File

@ -219,14 +219,6 @@ public:
std::vector<VIA_DIMENSION> m_ViasDimensionsList; std::vector<VIA_DIMENSION> m_ViasDimensionsList;
std::vector<DIFF_PAIR_DIMENSION> m_DiffPairDimensionsList; 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_MicroViasAllowed; ///< true to allow micro vias
bool m_BlindBuriedViaAllowed; ///< true to allow blind/buried vias bool m_BlindBuriedViaAllowed; ///< true to allow blind/buried vias
VIATYPE m_CurrentViaType; ///< (VIA_BLIND_BURIED, VIA_THROUGH, VIA_MICROVIA) VIATYPE m_CurrentViaType; ///< (VIA_BLIND_BURIED, VIA_THROUGH, VIA_MICROVIA)
@ -243,10 +235,9 @@ public:
int m_CopperEdgeClearance; int m_CopperEdgeClearance;
int m_HoleToHoleMin; // Min width of peninsula between two drilled holes int m_HoleToHoleMin; // Min width of peninsula between two drilled holes
std::map< int, int > m_DRCSeverities; // Map from DRCErrorCode to SEVERITY std::vector<DRC_RULE*> m_DRCRules;
std::map< int, int > m_DRCSeverities; // Map from DRCErrorCode to SEVERITY
/// Excluded DRC items std::set<wxString> m_DrcExclusions;
std::set<wxString> m_DrcExclusions;
/** Option to handle filled polygons in zones: /** Option to handle filled polygons in zones:
* the "legacy" option is using thick outlines around filled polygons: give the best shape * the "legacy" option is using thick outlines around filled polygons: give the best shape

View File

@ -354,4 +354,49 @@ protected:
DECLARE_ENUM_TO_WXANY( PCB_LAYER_ID ); DECLARE_ENUM_TO_WXANY( PCB_LAYER_ID );
#endif #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 */ #endif /* BOARD_ITEM_STRUCT_H */

View File

@ -57,20 +57,18 @@ class COMPILER;
struct ERROR_STATUS struct ERROR_STATUS
{ {
bool pendingError; bool pendingError;
enum STAGE { enum STAGE
CST_PARSE = 0, {
CST_CODEGEN, CST_PARSE = 0,
CST_RUNTIME CST_CODEGEN,
}; CST_RUNTIME
};
STAGE stage; STAGE stage;
std::string message; wxString message; // Note: use wxString for GUI-related strings
std::string failingObject; int srcPos;
int failingPosition;
std::string Format() const;
}; };
@ -108,158 +106,155 @@ struct TREE_NODE
UOP* uop; UOP* uop;
bool valid; bool valid;
bool isTerminal; bool isTerminal;
int srcPos;
}; };
static inline TREE_NODE* copyNode( TREE_NODE& t ) static inline TREE_NODE* copyNode( TREE_NODE& t )
{ {
auto t2 = new TREE_NODE(); auto t2 = new TREE_NODE();
t2->valid = t.valid; t2->valid = t.valid;
snprintf( t2->value.str, LIBEVAL_MAX_LITERAL_LENGTH, "%s", t.value.str ); snprintf( t2->value.str, LIBEVAL_MAX_LITERAL_LENGTH, "%s", t.value.str );
t2->op = t.op; t2->op = t.op;
t2->value.type = t.value.type; t2->value.type = t.value.type;
t2->leaf[0] = t.leaf[0]; t2->leaf[0] = t.leaf[0];
t2->leaf[1] = t.leaf[1]; t2->leaf[1] = t.leaf[1];
t2->isTerminal = false; t2->isTerminal = false;
t2->uop = nullptr; t2->srcPos = t.srcPos;
t2->uop = nullptr;
return t2; return t2;
} }
static inline TREE_NODE* newNode( int op, int type, const std::string& value ) static inline TREE_NODE* newNode( int op, int type, const std::string& value )
{ {
auto t2 = new TREE_NODE(); auto t2 = new TREE_NODE();
t2->valid = true; t2->valid = true;
snprintf( t2->value.str, LIBEVAL_MAX_LITERAL_LENGTH, "%s", value.c_str() ); snprintf( t2->value.str, LIBEVAL_MAX_LITERAL_LENGTH, "%s", value.c_str() );
t2->op = op; t2->op = op;
t2->value.type = type; t2->value.type = type;
t2->leaf[0] = nullptr; t2->leaf[0] = nullptr;
t2->leaf[1] = nullptr; t2->leaf[1] = nullptr;
t2->isTerminal = false; t2->isTerminal = false;
t2->uop = nullptr; t2->srcPos = -1;
t2->uop = nullptr;
return t2; return t2;
} }
class UNIT_RESOLVER { class UNIT_RESOLVER
public: {
UNIT_RESOLVER() public:
{ UNIT_RESOLVER()
} {
}
virtual ~UNIT_RESOLVER() virtual ~UNIT_RESOLVER()
{ {
} }
virtual const std::vector<std::string>& GetSupportedUnits() const virtual const std::vector<std::string>& GetSupportedUnits() const
{ {
static const std::vector<std::string> nullUnits; static const std::vector<std::string> nullUnits;
return nullUnits; return nullUnits;
} }
virtual double Convert( const std::string aString, int unitType ) const virtual double Convert( const std::string& aString, int unitType ) const
{ {
return 0.0; return 0.0;
}; };
}; };
class VALUE {
class VALUE
{
public: public:
VALUE(): VALUE():
m_type(VT_UNDEFINED), m_type(VT_UNDEFINED),
m_valueDbl( 0 ) m_valueDbl( 0 )
{}; {};
VALUE( const std::string& aStr ) : VALUE( std::string aStr ) :
m_type( VT_STRING ), m_type( VT_STRING ),
m_valueDbl( 0 ), m_valueDbl( 0 ),
m_valueStr( aStr ) m_valueStr( std::move( aStr ) )
{}; {};
VALUE( const double aVal ) : VALUE( const double aVal ) :
m_type( VT_NUMERIC ), m_type( VT_NUMERIC ),
m_valueDbl( aVal ) m_valueDbl( aVal )
{}; {};
double AsDouble() const double AsDouble() const
{ {
return m_valueDbl; return m_valueDbl;
} }
const std::string& AsString() const const std::string& AsString() const
{ {
return m_valueStr; return m_valueStr;
} }
bool operator==( const VALUE& b ) const bool operator==( const VALUE& b ) const
{ {
if( m_type != b.m_type ) if( m_type == VT_NUMERIC && b.m_type == VT_NUMERIC )
return false; return m_valueDbl == b.m_valueDbl;
if( m_type == VT_NUMERIC && m_valueDbl != b.m_valueDbl ) else if( m_type == VT_STRING && b.m_type == VT_STRING )
return false; return m_valueStr == b.m_valueStr;
if( m_type == VT_STRING && m_valueStr != b.m_valueStr )
return false;
return true; return false;
} }
VAR_TYPE_T GetType() const { return m_type; };
void Set( double aValue )
{
m_type = VT_NUMERIC;
m_valueDbl = aValue;
}
VAR_TYPE_T GetType() const { return m_type; }; void Set( const std::string& aValue )
{
m_type = VT_STRING;
m_valueStr = aValue;
}
void Set( double aValue ) void Set( const VALUE &val )
{ {
m_type = VT_NUMERIC; m_type = val.m_type;
m_valueDbl = aValue; m_valueDbl = val.m_valueDbl;
}
void Set( std::string aValue ) if( m_type == VT_STRING )
{
m_type = VT_STRING;
m_valueStr = aValue;
}
void Set( const VALUE &val )
{
m_type = val.m_type;
m_valueDbl = val.m_valueDbl;
if(m_type == VT_STRING)
m_valueStr = val.m_valueStr; m_valueStr = val.m_valueStr;
}
} bool EqualTo( const VALUE* v2 ) const
{
return operator==( *v2 );
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;
}
private: private:
VAR_TYPE_T m_type; VAR_TYPE_T m_type;
double m_valueDbl; double m_valueDbl;
std::string m_valueStr; std::string m_valueStr;
}; };
class UCODE; class UCODE;
class VAR_REF class VAR_REF
{ {
public: public:
virtual VAR_TYPE_T GetType( UCODE* aUcode ) = 0; virtual VAR_TYPE_T GetType() = 0;
virtual VALUE GetValue( UCODE* aUcode ) = 0; virtual VALUE GetValue( UCODE* aUcode ) = 0;
}; };
class UCODE class UCODE
{ {
public: public:
class CONTEXT class CONTEXT
{ {
public: public:
@ -268,7 +263,8 @@ public:
CONTEXT() CONTEXT()
{ {
m_sp = 0; m_sp = 0;
for (int i = 0; i < c_memSize; i++ )
for( int i = 0; i < c_memSize; i++ )
m_memory.push_back( VALUE() ); m_memory.push_back( VALUE() );
} }
@ -294,11 +290,12 @@ public:
{ {
return m_sp; return m_sp;
} }
private:
std::vector<VALUE> m_memory; private:
VALUE* m_stack[128]; std::vector<VALUE> m_memory;
int m_sp = 0; VALUE* m_stack[128];
int m_memPos = 0; int m_sp = 0;
int m_memPos = 0;
}; };
typedef std::function<void(UCODE*, CONTEXT*, void*)> FUNC_PTR; typedef std::function<void(UCODE*, CONTEXT*, void*)> FUNC_PTR;
@ -310,7 +307,7 @@ public:
VALUE* Run(); VALUE* Run();
std::string Dump() const; 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 ) virtual VAR_REF* createVarRef( COMPILER* aCompiler, const std::string& var, const std::string& field )
{ {
@ -328,21 +325,28 @@ private:
class UOP class UOP
{ {
public: public:
UOP( int op, void* arg ) : m_op( op ), m_arg( arg ) UOP( int op, void* arg ) :
{}; m_op( op ),
UOP( int op, UCODE::FUNC_PTR func, void *arg ) : m_op( op ), m_arg(arg), m_func( func ) m_arg( arg )
{}; {};
void Exec( UCODE::CONTEXT* ctx, UCODE *ucode ); UOP( int op, UCODE::FUNC_PTR func, void *arg ) :
std::string Format() const; m_op( op ),
m_arg(arg),
m_func( std::move( func ) )
{};
private: void Exec( UCODE::CONTEXT* ctx, UCODE *ucode );
int m_op;
void *m_arg; std::string Format() const;
UCODE::FUNC_PTR m_func;
}; private:
int m_op;
void* m_arg;
UCODE::FUNC_PTR m_func;
};
class TOKENIZER class TOKENIZER
{ {
@ -363,6 +367,7 @@ public:
{ {
if( m_pos >= m_str.length() ) if( m_pos >= m_str.length() )
return 0; return 0;
return m_str[m_pos]; return m_str[m_pos];
} }
@ -381,13 +386,13 @@ public:
return m_pos; return m_pos;
} }
std::string GetChars( std::function<bool( int )> cond ) const; 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: private:
std::string m_str; std::string m_str;
size_t m_pos; size_t m_pos;
}; };
@ -397,7 +402,8 @@ public:
COMPILER(); COMPILER();
virtual ~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. * will reset the parser. User defined variables are retained.
*/ */
void Clear(); void Clear();
@ -406,17 +412,18 @@ public:
void parseError( const char* s ); void parseError( const char* s );
void parseOk(); void parseOk();
int GetSourcePos() const { return m_sourcePos; }
/* Check if previous invokation of process() was successful */ /* Check if previous invokation of process() was successful */
inline bool IsValid() const inline bool IsValid() const
{ {
return !m_errorStatus.pendingError; return !m_errorStatus.pendingError;
} }
void setRoot( LIBEVAL::TREE_NODE root ); void setRoot( LIBEVAL::TREE_NODE root );
bool Compile( const std::string& aString, UCODE* aCode ); 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(); ERROR_STATUS GetErrorStatus();
protected: protected:
@ -446,9 +453,6 @@ protected:
bool lexDefault( T_TOKEN& aToken ); bool lexDefault( T_TOKEN& aToken );
bool lexString( T_TOKEN& aToken ); bool lexString( T_TOKEN& aToken );
/* Used by processing loop */
void parse( int token, TREE_NODE value );
int resolveUnits(); int resolveUnits();
UOP* makeUop( int op, double value ) UOP* makeUop( int op, double value )
@ -459,40 +463,35 @@ protected:
UOP* makeUop( int op, std::string value ) 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; return uop;
} }
UOP* makeUop( int op, VAR_REF* aRef = nullptr ) UOP* makeUop( int op, VAR_REF* aRef = nullptr )
{ {
auto uop = new UOP( op, aRef ); UOP* uop = new UOP( op, aRef );
return uop; return uop;
} }
UOP* makeUop( int op, UCODE::FUNC_PTR aFunc, void *arg = nullptr ) 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; return uop;
} }
/* Token state for input string. */ /* Token state for input string. */
void* m_parser; // the current lemon parser state machine void* m_parser; // the current lemon parser state machine
TOKENIZER m_tokenizer; TOKENIZER m_tokenizer;
char m_localeDecimalSeparator; 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;
std::unique_ptr<UNIT_RESOLVER> m_unitResolver; 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;
}; };

View File

@ -77,8 +77,11 @@ public:
/** /**
* Explodes the list of netclass assignments to include atomic members of composite labels * Explodes the list of netclass assignments to include atomic members of composite labels
* (buses). * (buses).
*
* @param aRebuildFromScratch indicates the assignments should be rebuilt from the netclass
* membership lists before resolving.
*/ */
void ResolveNetClassAssignments(); void ResolveNetClassAssignments( bool aRebuildFromScratch = false );
private: private:
// TODO: Add diff pairs, bus information, etc here. // TODO: Add diff pairs, bus information, etc here.

View File

@ -526,6 +526,11 @@ public:
return *this; return *this;
} }
void SetDefault( T aValue )
{
m_default = aValue;
}
const wxString& ToString( T value ) const const wxString& ToString( T value ) const
{ {
return m_choices.GetLabel( static_cast<int>( value ) ); return m_choices.GetLabel( static_cast<int>( value ) );
@ -533,7 +538,10 @@ public:
const T ToEnum( const wxString value ) 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 const wxPGChoices& Choices() const
@ -542,8 +550,9 @@ public:
} }
private: private:
wxPGChoices m_choices; wxPGChoices m_choices;
std::unordered_map<wxString, T> m_reverseMap; std::unordered_map<wxString, T> m_reverseMap;
T m_default; // Returned if the string is not recognized
ENUM_MAP<T>() ENUM_MAP<T>()
{ {

View File

@ -204,14 +204,14 @@ static struct BOARD_CONNECTED_ITEM_DESC
{ {
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 ) if( layerEnum.Choices().GetCount() == 0 )
{ {
layerEnum.SetDefault( UNDEFINED_LAYER );
for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq ) for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
{
layerEnum.Map( *seq, LSET::Name( *seq ) ); layerEnum.Map( *seq, LSET::Name( *seq ) );
}
} }
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();

View File

@ -590,9 +590,7 @@ void BOARD_DESIGN_SETTINGS::initFromOther( const BOARD_DESIGN_SETTINGS& aOther )
m_TrackWidthList = aOther.m_TrackWidthList; m_TrackWidthList = aOther.m_TrackWidthList;
m_ViasDimensionsList = aOther.m_ViasDimensionsList; m_ViasDimensionsList = aOther.m_ViasDimensionsList;
m_DiffPairDimensionsList = aOther.m_DiffPairDimensionsList; m_DiffPairDimensionsList = aOther.m_DiffPairDimensionsList;
m_DRCRuleSelectors = aOther.m_DRCRuleSelectors;
m_DRCRules = aOther.m_DRCRules; m_DRCRules = aOther.m_DRCRules;
m_matched = aOther.m_matched;
m_MicroViasAllowed = aOther.m_MicroViasAllowed; m_MicroViasAllowed = aOther.m_MicroViasAllowed;
m_BlindBuriedViaAllowed = aOther.m_BlindBuriedViaAllowed; m_BlindBuriedViaAllowed = aOther.m_BlindBuriedViaAllowed;
m_CurrentViaType = aOther.m_CurrentViaType; m_CurrentViaType = aOther.m_CurrentViaType;

View File

@ -48,52 +48,6 @@
#include <ratsnest/ratsnest_data.h> #include <ratsnest/ratsnest_data.h>
#include <ratsnest/ratsnest_viewitem.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 /* 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. * in class_board_item.cpp like I first tried it.
*/ */

View File

@ -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. * This program source code file is part of KiCad, a free EDA CAD application.
* *
@ -29,7 +24,6 @@
*/ */
#include <fctsys.h> #include <fctsys.h>
#include <common.h>
#include <pcbnew.h> #include <pcbnew.h>
#include <wx/debug.h> #include <wx/debug.h>
@ -137,8 +131,9 @@ void BOARD_ITEM::SwapData( BOARD_ITEM* aImage )
} }
void BOARD_ITEM::TransformShapeWithClearanceToPolygon( void BOARD_ITEM::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue, int aError, bool ignoreLineWidth ) const int aClearanceValue, int aError,
bool ignoreLineWidth ) const
{ {
wxASSERT_MSG( false, "Called TransformShapeWithClearanceToPolygon() on unsupported BOARD_ITEM." ); wxASSERT_MSG( false, "Called TransformShapeWithClearanceToPolygon() on unsupported BOARD_ITEM." );
}; };
@ -148,14 +143,14 @@ static struct BOARD_ITEM_DESC
{ {
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 ) if( layerEnum.Choices().GetCount() == 0 )
{ {
layerEnum.SetDefault( UNDEFINED_LAYER );
for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq ) for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
{
layerEnum.Map( *seq, LSET::Name( *seq ) ); layerEnum.Map( *seq, LSET::Name( *seq ) );
}
} }
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance(); PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();

View File

@ -1647,8 +1647,8 @@ static struct MODULE_DESC
&MODULE::SetValue, &MODULE::GetValue ) ); &MODULE::SetValue, &MODULE::GetValue ) );
propMgr.AddProperty( new PROPERTY<MODULE, double>( _( "Orientation" ), propMgr.AddProperty( new PROPERTY<MODULE, double>( _( "Orientation" ),
&MODULE::SetOrientationDegrees, &MODULE::GetOrientationDegrees, PROPERTY_DISPLAY::DEGREE ) ); &MODULE::SetOrientationDegrees, &MODULE::GetOrientationDegrees, PROPERTY_DISPLAY::DEGREE ) );
//propMgr.AddProperty( new PROPERTY<MODULE, int>( _( "Local Clearance" ), propMgr.AddProperty( new PROPERTY<MODULE, int>( _( "Local Clearance" ),
// &MODULE::SetLocalClearance, &MODULE::GetLocalClearance, PROPERTY_DISPLAY::DISTANCE ) ); &MODULE::SetLocalClearance, &MODULE::GetLocalClearance, PROPERTY_DISPLAY::DISTANCE ) );
propMgr.AddProperty( new PROPERTY<MODULE, int>( _( "Local Solderpaste Margin" ), propMgr.AddProperty( new PROPERTY<MODULE, int>( _( "Local Solderpaste Margin" ),
&MODULE::SetLocalSolderPasteMargin, &MODULE::GetLocalSolderPasteMargin, PROPERTY_DISPLAY::DISTANCE ) ); &MODULE::SetLocalSolderPasteMargin, &MODULE::GetLocalSolderPasteMargin, PROPERTY_DISPLAY::DISTANCE ) );
propMgr.AddProperty( new PROPERTY<MODULE, double>( _( "Local Solderpaste Margin Ratio" ), propMgr.AddProperty( new PROPERTY<MODULE, double>( _( "Local Solderpaste Margin Ratio" ),

View File

@ -237,7 +237,10 @@ public:
int GetLocalSolderMaskMargin() const { return m_LocalSolderMaskMargin; } int GetLocalSolderMaskMargin() const { return m_LocalSolderMaskMargin; }
void SetLocalSolderMaskMargin( int aMargin ) { m_LocalSolderMaskMargin = aMargin; } 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 ) if( aSource )
*aSource = wxString::Format( _( "footprint %s" ), GetReference() ); *aSource = wxString::Format( _( "footprint %s" ), GetReference() );
@ -245,8 +248,6 @@ public:
return m_LocalClearance; return m_LocalClearance;
} }
void SetLocalClearance( int aClearance ) { m_LocalClearance = aClearance; }
int GetLocalSolderPasteMargin() const { return m_LocalSolderPasteMargin; } int GetLocalSolderPasteMargin() const { return m_LocalSolderPasteMargin; }
void SetLocalSolderPasteMargin( int aMargin ) { m_LocalSolderPasteMargin = aMargin; } void SetLocalSolderPasteMargin( int aMargin ) { m_LocalSolderPasteMargin = aMargin; }

View File

@ -36,8 +36,7 @@ PANEL_PCBNEW_COLOR_SETTINGS::PANEL_PCBNEW_COLOR_SETTINGS( PCB_EDIT_FRAME* aFrame
: PANEL_COLOR_SETTINGS( aParent ), : PANEL_COLOR_SETTINGS( aParent ),
m_frame( aFrame ), m_frame( aFrame ),
m_page( nullptr ), m_page( nullptr ),
m_titleBlock( nullptr ), m_titleBlock( nullptr )
m_ws( nullptr )
{ {
// Currently this only applies to eeschema // Currently this only applies to eeschema
m_optOverrideColors->Hide(); m_optOverrideColors->Hide();

View File

@ -61,8 +61,6 @@ private:
TITLE_BLOCK* m_titleBlock; TITLE_BLOCK* m_titleBlock;
KIGFX::WS_PROXY_VIEW_ITEM* m_ws;
void createSwatches(); void createSwatches();
}; };

View File

@ -189,12 +189,11 @@ bool PANEL_SETUP_RULES::TransferDataFromWindow()
try try
{ {
std::vector<DRC_SELECTOR*> dummySelectors;
std::vector<DRC_RULE*> dummyRules; std::vector<DRC_RULE*> dummyRules;
DRC_RULES_PARSER parser( m_frame->GetBoard(), m_textEditor->GetText(), _( "DRC rules" ) ); DRC_RULES_PARSER parser( m_frame->GetBoard(), m_textEditor->GetText(), _( "DRC rules" ) );
parser.Parse( dummySelectors, dummyRules ); parser.Parse( dummyRules );
} }
catch( PARSE_ERROR& pe ) catch( PARSE_ERROR& pe )
{ {
@ -249,7 +248,7 @@ void PANEL_SETUP_RULES::OnSyntaxHelp( wxHyperlinkEvent& aEvent )
"<pre>" "<pre>"
"(rule \"copper keepout\"\r" "(rule \"copper keepout\"\r"
" (disallow track) (disallow via) (disallow zone)\r" " (disallow track) (disallow via) (disallow zone)\r"
" (condition \"A.name == no_copper\"))\r" " (condition \"A.name == 'no_copper'\"))\r"
"\r" "\r"
"(rule \"BGA neckdown\"\r" "(rule \"BGA neckdown\"\r"
" (constraint track_width (min 0.2mm) (opt 0.25mm))\r" " (constraint track_width (min 0.2mm) (opt 0.25mm))\r"
@ -258,11 +257,11 @@ void PANEL_SETUP_RULES::OnSyntaxHelp( wxHyperlinkEvent& aEvent )
"\r" "\r"
"(rule HV\r" "(rule HV\r"
" (constraint clearance (min 1.5mm))\r" " (constraint clearance (min 1.5mm))\r"
" (condition \"A.netclass == HV\"))\r" " (condition \"A.netclass == 'HV'\"))\r"
"\r" "\r"
"(rule HV_HV\r" "(rule HV_HV\r"
" (constraint clearance (min 2.0mm))\r" " (constraint clearance (min 2.0mm))\r"
" (condition \"A.netclass == HV && B.netclass == HV\"))\r" " (condition \"A.netclass == 'HV' && B.netclass == 'HV'\"))\r"
"</pre>"; "</pre>";
HTML_MESSAGE_BOX dlg( m_parent, _( "Syntax Help" ) ); HTML_MESSAGE_BOX dlg( m_parent, _( "Syntax Help" ) );

View File

@ -187,7 +187,6 @@ bool DRC::LoadRules()
if( rulesFile.FileExists() ) if( rulesFile.FileExists() )
{ {
m_ruleSelectors.clear();
m_rules.clear(); m_rules.clear();
FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) ); FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) );
@ -197,12 +196,11 @@ bool DRC::LoadRules()
try try
{ {
DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath ); DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath );
parser.Parse( m_ruleSelectors, m_rules ); parser.Parse( m_rules );
} }
catch( PARSE_ERROR& pe ) catch( PARSE_ERROR& pe )
{ {
// Don't leave possibly malformed stuff around for us to trip over // Don't leave possibly malformed stuff around for us to trip over
m_ruleSelectors.clear();
m_rules.clear(); m_rules.clear();
wxSafeYield( m_editFrame ); 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(); BOARD_DESIGN_SETTINGS& bds = m_pcb->GetDesignSettings();
bds.m_DRCRuleSelectors = m_ruleSelectors;
bds.m_DRCRules = m_rules; bds.m_DRCRules = m_rules;
return true; return true;

View File

@ -132,7 +132,6 @@ private:
bool m_drcRun; // indicates DRC has been run at least once bool m_drcRun; // indicates DRC has been run at least once
bool m_footprintsTested; // indicates footprints were tested in last run bool m_footprintsTested; // indicates footprints were tested in last run
std::vector<DRC_SELECTOR*> m_ruleSelectors;
std::vector<DRC_RULE*> m_rules; std::vector<DRC_RULE*> m_rules;
// Temp variables for performance during a single DRC run // Temp variables for performance during a single DRC run

View File

@ -27,6 +27,8 @@
#include <board_design_settings.h> #include <board_design_settings.h>
#include <class_board.h> #include <class_board.h>
#include <class_board_item.h> #include <class_board_item.h>
#include <pcb_expr_evaluator.h>
/* /*
* Rule tokens: * Rule tokens:
@ -52,8 +54,17 @@
* hole * hole
* *
* *
* (rule "HV" (constraint clearance (min 200))) * (rule "HV"
* (rule "HV_external" (constraint clearance (min 400))) * (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" (constraint clearance (min 200)))
* (rule "HV2HV_external" (constraint clearance (min 500))) * (rule "HV2HV_external" (constraint clearance (min 500)))
* (rule "pad2padHV" (constraint clearance (min 500))) * (rule "pad2padHV" (constraint clearance (min 500)))
@ -62,99 +73,83 @@
* (rule "neckdown" (constraint clearance (min 15))) * (rule "neckdown" (constraint clearance (min 15)))
* *
* (rule "disallowMicrovias" (disallow micro_via)) * (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 ) 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(); BOARD* board = aItem->GetBoard();
if( !board ) if( !board )
return nullptr; return nullptr;
NETCLASS* aNetclass = nullptr; for( DRC_RULE* rule : board->GetDesignSettings().m_DRCRules )
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 )
{ {
if( candidate->m_MatchNetclasses.size() == 2 ) if( ( rule->m_ConstraintFlags & aConstraint ) > 0 )
{ {
if( !bItem ) if( rule->m_Condition.EvaluateFor( aItem, bItem ) )
continue; return rule;
NETCLASS* firstNetclass = candidate->m_MatchNetclasses[0].get();
NETCLASS* secondNetclass = candidate->m_MatchNetclasses[1].get();
if( !( aNetclass == firstNetclass && bNetclass == secondNetclass )
&& !( aNetclass == secondNetclass && bNetclass == firstNetclass ) )
{
continue;
}
} }
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; 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;
}

View File

@ -27,9 +27,11 @@
#include <core/typeinfo.h> #include <core/typeinfo.h>
#include <netclass.h> #include <netclass.h>
#include <layers_id_colors_and_visibility.h> #include <layers_id_colors_and_visibility.h>
#include <libeval_compiler/libeval_compiler.h>
class BOARD_ITEM; class BOARD_ITEM;
class PCB_EXPR_UCODE;
#define CLEARANCE_CONSTRAINT (1 << 0) #define CLEARANCE_CONSTRAINT (1 << 0)
@ -50,6 +52,52 @@ class BOARD_ITEM;
#define DISALLOW_FOOTPRINTS (1 << 9) #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 class DRC_RULE
{ {
public: public:
@ -81,31 +129,11 @@ public:
MINOPTMAX m_TrackConstraint; MINOPTMAX m_TrackConstraint;
int m_MinHole; int m_MinHole;
wxString m_Condition; DRC_RULE_CONDITION 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* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint ); DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint );
#endif // DRC_RULE_H #endif // DRC_RULE_H

View File

@ -65,10 +65,8 @@ void DRC_RULES_PARSER::initLayerMap()
} }
void DRC_RULES_PARSER::Parse( std::vector<DRC_SELECTOR*>& aSelectors, void DRC_RULES_PARSER::Parse( std::vector<DRC_RULE*>& aRules )
std::vector<DRC_RULE*>& aRules )
{ {
std::vector< std::pair<DRC_SELECTOR*, wxString> > selectorRules;
bool haveVersion = false; bool haveVersion = false;
for( T token = NextTok(); token != T_EOF; token = NextTok() ) for( T token = NextTok(); token != T_EOF; token = NextTok() )
@ -91,15 +89,6 @@ void DRC_RULES_PARSER::Parse( std::vector<DRC_SELECTOR*>& aSelectors,
NeedRIGHT(); NeedRIGHT();
break; break;
case T_selector:
{
wxString ruleName;
aSelectors.push_back( parseDRC_SELECTOR( &ruleName ) );
selectorRules.emplace_back( aSelectors.back(), ruleName );
}
break;
case T_rule: case T_rule:
aRules.push_back( parseDRC_RULE() ); aRules.push_back( parseDRC_RULE() );
break; break;
@ -108,118 +97,6 @@ void DRC_RULES_PARSER::Parse( std::vector<DRC_SELECTOR*>& aSelectors,
Expecting( "selector or rule" ); 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: case T_condition:
NeedSYMBOL(); 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(); NeedRIGHT();
break; break;

View File

@ -43,13 +43,11 @@ public:
DRC_RULES_PARSER( BOARD* aBoard, const wxString& aSource, const wxString& aSourceDescr ); DRC_RULES_PARSER( BOARD* aBoard, const wxString& aSource, const wxString& aSourceDescr );
DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxString& aFilename ); 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: private:
void initLayerMap(); void initLayerMap();
DRC_SELECTOR* parseDRC_SELECTOR( wxString* aRuleName );
DRC_RULE* parseDRC_RULE(); DRC_RULE* parseDRC_RULE();
void parseConstraint( DRC_RULE* aRule ); void parseConstraint( DRC_RULE* aRule );

View File

@ -653,7 +653,7 @@ void PCB_EDIT_FRAME::ShowBoardSetupDialog( const wxString& aInitialPage, const w
if( dlg.ShowQuasiModal() == wxID_OK ) if( dlg.ShowQuasiModal() == wxID_OK )
{ {
Prj().GetProjectFile().NetSettings().ResolveNetClassAssignments(); Prj().GetProjectFile().NetSettings().ResolveNetClassAssignments( true );
GetBoard()->SynchronizeNetsAndNetClasses(); GetBoard()->SynchronizeNetsAndNetClasses();
GetBoard()->GetDesignSettings().SetCurrentNetClass( NETCLASS::Default ); GetBoard()->GetDesignSettings().SetCurrentNetClass( NETCLASS::Default );

View File

@ -23,92 +23,94 @@
#include <cstdio> #include <cstdio>
#include <boost/algorithm/string/case_conv.hpp>
#include "class_board.h" #include "class_board.h"
#include "pcb_expr_evaluator.h" #include "pcb_expr_evaluator.h"
class PCB_EXPR_BUILTIN_FUNCTIONS 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; D_PAD* pad = static_cast<D_PAD*>( item );
return self; result = pad->GetAttribute() == PAD_ATTRIB_STANDARD;
} }
std::string tolower( const std::string str ) const LIBEVAL::VALUE* rv = aCtx->AllocValue();
{ rv->Set( result ? 1.0 : 0.0 );
std::string rv; aCtx->Push( 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 );
}
}; };
PCB_EXPR_BUILTIN_FUNCTIONS::PCB_EXPR_BUILTIN_FUNCTIONS() PCB_EXPR_BUILTIN_FUNCTIONS::PCB_EXPR_BUILTIN_FUNCTIONS()
{ {
m_funcs[ "onlayer" ] = onLayer; m_funcs[ "onlayer" ] = onLayer;
m_funcs[ "isplated" ] = isPlated; m_funcs[ "isplated" ] = isPlated;
} }
BOARD_ITEM* PCB_EXPR_VAR_REF::GetObject( LIBEVAL::UCODE* aUcode ) const BOARD_ITEM* PCB_EXPR_VAR_REF::GetObject( LIBEVAL::UCODE* aUcode ) const
{ {
auto ucode = static_cast<const PCB_EXPR_UCODE*>( aUcode ); const PCB_EXPR_UCODE* ucode = static_cast<const PCB_EXPR_UCODE*>( aUcode );
auto item = ucode->GetItem( m_itemIndex ); BOARD_ITEM* item = ucode->GetItem( m_itemIndex );
return item; return item;
} }
LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode ) LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::UCODE* aUcode )
{ {
auto item = GetObject( aUcode ); BOARD_ITEM* item = const_cast<BOARD_ITEM*>( GetObject( aUcode ) );
auto it = m_matchingTypes.find( TYPE_HASH( *item ) ); auto it = m_matchingTypes.find( TYPE_HASH( *item ) );
if( it == m_matchingTypes.end() ) 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() ); //printf("item %p Get string '%s'\n", item, (const char*) it->second->Name().c_str() );
str = item->Get<wxString>( it->second ); str = item->Get<wxString>( it->second );
} else { }
else
{
const auto& any = item->Get( it->second ); const auto& any = item->Get( it->second );
any.GetAs<wxString>( &str ); any.GetAs<wxString>( &str );
//printf("item %p get enum: '%s'\n", item , (const char*) str.c_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(); PCB_EXPR_BUILTIN_FUNCTIONS& registry = PCB_EXPR_BUILTIN_FUNCTIONS::Instance();
auto f = registry.Get( name );
auto f = registry.Get( boost::to_lower_copy( name ) );
return f; return f;
} }
LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler, 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(); PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
PCB_EXPR_VAR_REF* vref = nullptr;
auto classes = propMgr.GetAllClasses(); if( var == "A" )
auto vref = new PCB_EXPR_VAR_REF( var == "A" ? 0 : 1 ); {
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 if( field.empty() ) // return reference to base object
return vref; return vref;
for( auto cls : classes ) for( const PROPERTY_MANAGER::CLASS_INFO& cls : propMgr.GetAllClasses() )
{ {
if( propMgr.IsOfType( cls.type, TYPE_HASH( BOARD_ITEM ) ) ) 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() ); //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 ); vref->AddAllowedClass( cls.type, prop );
if( prop->TypeHash() == TYPE_HASH( int ) ) if( prop->TypeHash() == TYPE_HASH( int ) )
{
vref->SetType( LIBEVAL::VT_NUMERIC ); vref->SetType( LIBEVAL::VT_NUMERIC );
}
else if( prop->TypeHash() == TYPE_HASH( wxString ) ) else if( prop->TypeHash() == TYPE_HASH( wxString ) )
{
vref->SetType( LIBEVAL::VT_STRING ); vref->SetType( LIBEVAL::VT_STRING );
}
else if ( prop->HasChoices() ) else if ( prop->HasChoices() )
{ // it's an enum, we treat it as string { // it's an enum, we treat it as string
vref->SetType( LIBEVAL::VT_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; return vref;
} }
@ -204,19 +232,16 @@ public:
return pcbUnits; 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() ); double v = atof( aString.c_str() );
switch( unitId ) switch( unitId )
{ {
case 0: case 0: return Mils2iu( v );
return Mils2iu( v ); case 1: return Millimeter2iu( v );
case 1: case 2: return Mils2iu( v * 1000.0 );
return Millimeter2iu( v ); default: return v;
case 2:
return Mils2iu( v * 1000.0 );
default:
return v;
} }
}; };
}; };

View File

@ -66,6 +66,7 @@ class PCB_EXPR_VAR_REF : public LIBEVAL::VAR_REF
public: public:
PCB_EXPR_VAR_REF( int aItemIndex ) : PCB_EXPR_VAR_REF( int aItemIndex ) :
m_itemIndex( aItemIndex ), m_itemIndex( aItemIndex ),
m_type( LIBEVAL::VT_UNDEFINED ),
m_isEnum( false ) m_isEnum( false )
{ {
//printf("*** createVarRef %p %d\n", this, aItemIndex ); //printf("*** createVarRef %p %d\n", this, aItemIndex );
@ -84,7 +85,7 @@ public:
m_matchingTypes[type_hash] = prop; 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; return m_type;
} }
@ -98,7 +99,7 @@ private:
std::unordered_map<TYPE_ID, PROPERTY_BASE*> m_matchingTypes; std::unordered_map<TYPE_ID, PROPERTY_BASE*> m_matchingTypes;
int m_itemIndex; int m_itemIndex;
LIBEVAL::VAR_TYPE_T m_type; LIBEVAL::VAR_TYPE_T m_type;
bool m_isEnum; bool m_isEnum;
}; };
@ -116,10 +117,7 @@ public:
~PCB_EXPR_EVALUATOR(); ~PCB_EXPR_EVALUATOR();
bool Evaluate( const wxString& aExpr ); bool Evaluate( const wxString& aExpr );
int Result() const int Result() const { return m_result; }
{
return m_result;
}
wxString GetErrorString(); wxString GetErrorString();
private: private:

View File

@ -186,7 +186,6 @@ bool DRC::LoadRules()
if( rulesFile.FileExists() ) if( rulesFile.FileExists() )
{ {
m_ruleSelectors.clear();
m_rules.clear(); m_rules.clear();
FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) ); FILE* fp = wxFopen( rulesFilepath, wxT( "rt" ) );
@ -196,12 +195,11 @@ bool DRC::LoadRules()
try try
{ {
DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath ); DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath );
parser.Parse( m_ruleSelectors, m_rules ); parser.Parse( m_rules );
} }
catch( PARSE_ERROR& pe ) catch( PARSE_ERROR& pe )
{ {
// Don't leave possibly malformed stuff around for us to trip over // Don't leave possibly malformed stuff around for us to trip over
m_ruleSelectors.clear();
m_rules.clear(); m_rules.clear();
wxSafeYield( m_editFrame ); wxSafeYield( m_editFrame );

View File

@ -47,23 +47,26 @@ test::DRC_RULE_CONDITION::DRC_RULE_CONDITION()
m_ucode = nullptr; m_ucode = nullptr;
} }
test::DRC_RULE_CONDITION::~DRC_RULE_CONDITION() 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 // fixme: handle error conditions
return m_ucode->Run()->AsDouble() != 0.0; return m_ucode->Run()->AsDouble() != 0.0;
} }
bool test::DRC_RULE_CONDITION::Compile() bool test::DRC_RULE_CONDITION::Compile()
{ {
PCB_EXPR_COMPILER compiler; PCB_EXPR_COMPILER compiler;
if (!m_ucode) if (!m_ucode)
m_ucode = new PCB_EXPR_UCODE; m_ucode = new PCB_EXPR_UCODE;
@ -74,11 +77,12 @@ bool test::DRC_RULE_CONDITION::Compile()
m_compileError = compiler.GetErrorStatus(); m_compileError = compiler.GetErrorStatus();
printf("Fail: %s", m_compileError.Format().c_str() ); printf( "Fail: %s", m_compileError.Format().c_str() );
return false; return false;
} }
LIBEVAL::ERROR_STATUS test::DRC_RULE_CONDITION::GetCompilationError() LIBEVAL::ERROR_STATUS test::DRC_RULE_CONDITION::GetCompilationError()
{ {
return m_compileError; return m_compileError;

View File

@ -130,7 +130,7 @@ public:
DRC_RULE_CONDITION(); DRC_RULE_CONDITION();
~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(); bool Compile();
LIBEVAL::ERROR_STATUS GetCompilationError(); LIBEVAL::ERROR_STATUS GetCompilationError();
@ -140,7 +140,7 @@ public:
private: private:
LIBEVAL::ERROR_STATUS m_compileError; LIBEVAL::ERROR_STATUS m_compileError;
PCB_EXPR_UCODE* m_ucode; PCB_EXPR_UCODE* m_ucode;
}; };

View File

@ -118,20 +118,20 @@ int main( int argc, char *argv[] )
trackA.SetWidth( Mils2iu( 10 )); trackA.SetWidth( Mils2iu( 10 ));
trackB.SetWidth( Mils2iu( 20 )); trackB.SetWidth( Mils2iu( 20 ));
printf("TrkA %p netclass '%s'\n", &trackA, (const char*) trackA.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() ); 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.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.type == 'Pad' && B.type == 'Pad' && (A.onLayer('F.Cu'))", VAL( 0.0 ), false, &trackA, &trackB );
return 0; return 0;
testEvalExpr( "A.Width > B.Width", VAL(0.0), 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.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", 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.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; return 0;
} }