Hook libeval compiler up to rule parser
- convert expression string tokens to single-quote-delimited - fix bug where netclass assignments weren't getting updated after board setup dialog - move property manager rebuild to lazy evaluation - improve performance with wider use of const& - retire DRC_SELECTOR stuff - use wxString for GUI stuff (particularly translated stuff) - fix EqualTo() to return false instead of asserting when op types don't match - fix buffer overruns with fixed-size string buffers - make expression function calls case-insensitive - integrate expression errors into rule parser - produce more and better error messages - keep BOARD_ITEM ptrs const as long as possible - fix a couple of uninitialized variables
This commit is contained in:
parent
6d8fb94d86
commit
095937563b
|
@ -971,114 +971,114 @@ static YYACTIONTYPE yy_reduce(
|
||||||
break;
|
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;
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -224,26 +223,29 @@ std::vector<TYPE_ID> PROPERTY_MANAGER::GetMatchingClasses( PROPERTY_BASE* aPrope
|
||||||
for( auto prop : cls.second.m_allProperties )
|
for( auto prop : cls.second.m_allProperties )
|
||||||
info.properties.push_back(prop);
|
info.properties.push_back(prop);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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; };
|
||||||
|
|
||||||
VAR_TYPE_T GetType() const { return m_type; };
|
void Set( double aValue )
|
||||||
|
{
|
||||||
|
m_type = VT_NUMERIC;
|
||||||
|
m_valueDbl = aValue;
|
||||||
|
}
|
||||||
|
|
||||||
void Set( double aValue )
|
void Set( const std::string& aValue )
|
||||||
{
|
{
|
||||||
m_type = VT_NUMERIC;
|
m_type = VT_STRING;
|
||||||
m_valueDbl = aValue;
|
m_valueStr = aValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Set( std::string aValue )
|
void Set( const VALUE &val )
|
||||||
{
|
{
|
||||||
m_type = VT_STRING;
|
m_type = val.m_type;
|
||||||
m_valueStr = aValue;
|
m_valueDbl = val.m_valueDbl;
|
||||||
}
|
|
||||||
|
|
||||||
void Set( const VALUE &val )
|
if( m_type == VT_STRING )
|
||||||
{
|
|
||||||
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
|
||||||
bool EqualTo( const VALUE* v2 ) const
|
{
|
||||||
{
|
return operator==( *v2 );
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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>()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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" ),
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -61,8 +61,6 @@ private:
|
||||||
|
|
||||||
TITLE_BLOCK* m_titleBlock;
|
TITLE_BLOCK* m_titleBlock;
|
||||||
|
|
||||||
KIGFX::WS_PROXY_VIEW_ITEM* m_ws;
|
|
||||||
|
|
||||||
void createSwatches();
|
void createSwatches();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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" ) );
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue