Report all DRC rule errors, not just the first.

This commit is contained in:
Jeff Young 2020-07-30 12:24:29 +01:00
parent ebef7c03db
commit 577c1be391
21 changed files with 744 additions and 319 deletions

View File

@ -10,10 +10,6 @@ graphic
hole
inner
layer
match_area
match_layer
match_netclass
match_type
max
micro_via
min

View File

@ -26,6 +26,7 @@
#include <stdarg.h>
#endif
#include <reporter.h>
#include <libeval_compiler/libeval_compiler.h>
/* The (generated) lemon parser is written in C.
@ -150,13 +151,6 @@ std::string UCODE::Dump() const
};
void CONTEXT::ReportError( const wxString& aErrorMsg )
{
m_errorStatus.pendingError = true;
m_errorStatus.message = aErrorMsg;
}
std::string TOKENIZER::GetChars( std::function<bool( int )> cond ) const
{
std::string rv;
@ -186,7 +180,10 @@ bool TOKENIZER::MatchAhead( const std::string& match, std::function<bool( int )>
}
COMPILER::COMPILER()
COMPILER::COMPILER( REPORTER* aReporter, int aSourceLine, int aSourceOffset ) :
m_reporter( aReporter ),
m_originLine( aSourceLine ),
m_originOffset( aSourceOffset )
{
m_localeDecimalSeparator = '.';
m_sourcePos = 0;
@ -224,9 +221,7 @@ void COMPILER::Clear()
void COMPILER::parseError( const char* s )
{
libeval_dbg(0, "PARSE ERROR: %s\n", s );
m_errorStatus.pendingError = true;
m_errorStatus.message = s;
reportError( s );
}
@ -241,7 +236,6 @@ bool COMPILER::Compile( const std::string& aString, UCODE* aCode, CONTEXT* aPref
// Feed parser token after token until end of input.
newString( aString );
m_errorStatus.pendingError = false;
if( m_tree )
{
@ -268,14 +262,6 @@ bool COMPILER::Compile( const std::string& aString, UCODE* aCode, CONTEXT* aPref
libeval_dbg(10, "parse: tok %d\n", tok.token );
Parse( m_parser, tok.token, tok.value, this );
if( m_errorStatus.pendingError )
{
m_errorStatus.stage = ERROR_STATUS::CST_PARSE;
m_errorStatus.message.Printf( _( "Unrecognized token '%s'" ), tok.value.value.str );
m_errorStatus.srcPos = m_tokenizer.GetPos();
return false;
}
if( m_parseFinished || tok.token == G_ENDS )
{
// Reset parser by passing zero as token ID, value is ignored.
@ -359,6 +345,7 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken )
T_TOKEN retval;
std::string current;
int convertFrom;
wxString msg;
retval.token = G_ENDS;
@ -495,8 +482,6 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken )
}
else
{
//printf( "WTF: '%c'\n", ch );
// Single char tokens
switch( ch )
{
@ -513,9 +498,7 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken )
case '.': retval.token = G_STRUCT_REF; break;
default:
m_errorStatus.stage = ERROR_STATUS::CST_PARSE;
m_errorStatus.message.Printf( _( "Unrecognized character '%c'" ), (char) ch );
m_errorStatus.srcPos = m_tokenizer.GetPos();
reportError( wxString::Format( _( "Unrecognized character '%c'" ), (char) ch ) );
break;
}
@ -526,6 +509,7 @@ bool COMPILER::lexDefault( COMPILER::T_TOKEN& aToken )
return true;
}
const std::string formatNode( TREE_NODE* tok )
{
// printf("fmt tok %p v %p ", tok, tok->value.v );
@ -598,10 +582,20 @@ void dumpNode( std::string& buf, TREE_NODE* tok, int depth = 0 )
}
void COMPILER::ReportError( const wxString& aErrorMsg )
void COMPILER::reportError( const wxString& aErrorMsg, int aPos )
{
m_errorStatus.pendingError = true;
m_errorStatus.message = aErrorMsg;
if( aPos == -1 )
aPos = m_sourcePos;
wxString rest;
wxString first = aErrorMsg.BeforeFirst( '|', &rest );
wxString msg = wxString::Format( _( "ERROR: <a href='%d:%d'>%s</a>%s" ),
m_originLine,
m_originOffset + aPos,
first,
rest );
m_reporter->Report( msg, RPT_SEVERITY_ERROR );
}
@ -624,6 +618,7 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
{
std::vector<TREE_NODE*> stack;
std::set<TREE_NODE*> visitedNodes;
wxString msg;
auto visited = [&]( TREE_NODE* node ) -> bool
{
@ -663,26 +658,19 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
{
char* itemName = node->leaf[0]->value.str;
char* propName = node->leaf[1]->value.str;
VAR_REF* vref = aCode->createVarRef( this, itemName, propName );
VAR_REF* vref = aCode->CreateVarRef( itemName, propName );
if( m_errorStatus.pendingError )
if( !vref )
{
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 );
msg.Printf( _( "Unrecognized item '%s'" ), itemName );
reportError( msg, node->leaf[0]->srcPos - (int) strlen( itemName ) );
return false;
}
if( vref->GetType() == VT_PARSE_ERROR )
{
msg.Printf( _( "Unrecognized property '%s'" ), propName );
reportError( msg, node->leaf[1]->srcPos - (int) strlen( propName ) );
return false;
}
@ -693,26 +681,22 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
case TR_OP_FUNC_CALL:
{
char* itemName = node->leaf[0]->value.str;
VAR_REF* vref = aCode->createVarRef( this, itemName, "" );
VAR_REF* vref = aCode->CreateVarRef( itemName, "" );
if( m_errorStatus.pendingError )
if( !vref )
{
m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN;
m_errorStatus.message.Printf( _( "Unrecognized item '%s'" ), itemName );
m_errorStatus.srcPos = node->leaf[0]->srcPos - strlen( itemName );
msg.Printf( _( "Unrecognized item '%s'" ), itemName );
reportError( msg, node->leaf[0]->srcPos - (int) strlen( itemName ) );
return false;
}
char* functionName = node->leaf[1]->leaf[0]->value.str;
auto func = aCode->createFuncCall( this, functionName );
auto func = aCode->CreateFuncCall( functionName );
if( !func )
{
m_errorStatus.pendingError = true;
m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN;
m_errorStatus.message.Printf( _( "Unrecognized function '%s'" ),
functionName );
m_errorStatus.srcPos = node->leaf[1]->leaf[0]->srcPos + 1;
msg.Printf( _( "Unrecognized function '%s'" ), functionName );
reportError( msg, node->leaf[1]->leaf[0]->srcPos + 1 );
return false;
}
@ -730,18 +714,18 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
{
}
if( aPreflightContext->GetErrorStatus().pendingError )
{
m_errorStatus = aPreflightContext->GetErrorStatus();
m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN;
m_errorStatus.srcPos = node->leaf[1]->leaf[0]->srcPos + 1;
return false;
}
/* SREF -> FUNC_CALL -> leaf0/1 */
node->leaf[1]->leaf[0]->leaf[0] = nullptr;
node->leaf[1]->leaf[0]->leaf[1] = nullptr;
if( !aPreflightContext->GetError().IsEmpty() )
{
reportError( aPreflightContext->GetError(),
node->leaf[1]->leaf[1]->srcPos
- (int) strlen( node->value.str ) - 1 );
return false;
}
visitedNodes.insert( node->leaf[0] );
visitedNodes.insert( node->leaf[1]->leaf[0] );
@ -782,20 +766,12 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
case TR_IDENTIFIER:
{
VAR_REF* vref = aCode->createVarRef( this, node->value.str, "" );
VAR_REF* vref = aCode->CreateVarRef( node->value.str, "" );
if( m_errorStatus.pendingError )
if( !vref )
{
m_errorStatus.pendingError = true;
m_errorStatus.stage = ERROR_STATUS::CST_CODEGEN;
if( m_errorStatus.message == "var" )
{
m_errorStatus.message.Printf( _( "Unrecognized item '%s'" ),
node->value.str );
m_errorStatus.srcPos = node->srcPos - strlen( node->value.str );
}
msg.Printf( _( "Unrecognized item '%s'" ), node->value.str );
reportError( msg, node->leaf[0]->srcPos - (int) strlen( node->value.str ) );
return false;
}

View File

@ -77,7 +77,8 @@ enum VAR_TYPE_T
{
VT_STRING = 1,
VT_NUMERIC,
VT_UNDEFINED
VT_UNDEFINED,
VT_PARSE_ERROR
};
enum TOKEN_TYPE_T
@ -287,13 +288,13 @@ public:
return m_stack.size();
}
ERROR_STATUS GetErrorStatus() const { return m_errorStatus; }
void ReportError( const wxString& aErrorMsg );
void ReportError( const wxString& aErrorMsg ) { m_errorMessage = aErrorMsg; }
const wxString& GetError() const { return m_errorMessage; }
private:
std::vector<VALUE*> m_ownedValues;
std::stack<VALUE*> m_stack;
ERROR_STATUS m_errorStatus;
wxString m_errorMessage;
};
@ -312,12 +313,12 @@ public:
VALUE* Run( CONTEXT* ctx );
std::string Dump() const;
virtual VAR_REF* createVarRef( COMPILER* aCompiler, const char* var, const char* field )
virtual VAR_REF* CreateVarRef( const char* var, const char* field )
{
return nullptr;
};
virtual FUNC_PTR createFuncCall( COMPILER* aCompiler, const char* name )
virtual FUNC_PTR CreateFuncCall( const char* name )
{
return nullptr;
};
@ -402,7 +403,7 @@ private:
class COMPILER
{
public:
COMPILER();
COMPILER( REPORTER* aReporter, int aSourceLine, int aSourceOffset );
virtual ~COMPILER();
/*
@ -417,18 +418,10 @@ public:
int GetSourcePos() const { return m_sourcePos; }
/* Check if previous invokation of process() was successful */
inline bool IsValid() const
{
return !m_errorStatus.pendingError;
}
void setRoot( LIBEVAL::TREE_NODE root );
void freeTree( LIBEVAL::TREE_NODE *tree );
bool Compile( const std::string& aString, UCODE* aCode, CONTEXT* aPreflightContext );
void ReportError( const wxString& aErrorMsg );
ERROR_STATUS GetErrorStatus() const { return m_errorStatus; }
protected:
enum LEXER_STATE
@ -441,6 +434,7 @@ protected:
bool generateUCode( UCODE* aCode, CONTEXT* aPreflightContext );
void reportError( const wxString& aErrorMsg, int aPos = -1 );
/* Token type used by the tokenizer */
struct T_TOKEN
@ -483,8 +477,8 @@ protected:
return uop;
}
protected:
/* Token state for input string. */
void* m_parser; // the current lemon parser state machine
TOKENIZER m_tokenizer;
char m_localeDecimalSeparator;
@ -492,9 +486,12 @@ protected:
std::unique_ptr<UNIT_RESOLVER> m_unitResolver;
int m_sourcePos;
ERROR_STATUS m_errorStatus;
bool m_parseFinished;
REPORTER* m_reporter;
int m_originLine; // Location in the file of the start of the expression
int m_originOffset;
TREE_NODE* m_tree;
};

View File

@ -21,6 +21,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <bitmaps.h>
#include <widgets/paged_dialog.h>
#include <pcb_edit_frame.h>
#include <pcb_expr_evaluator.h>
@ -28,6 +29,7 @@
#include <tool/tool_manager.h>
#include <drc/drc.h>
#include <panel_setup_rules.h>
#include <wx_html_report_box.h>
#include <html_messagebox.h>
#include <scintilla_tricks.h>
#include <drc/drc_rule_parser.h>
@ -47,6 +49,8 @@ PANEL_SETUP_RULES::PANEL_SETUP_RULES( PAGED_DIALOG* aParent, PCB_EDIT_FRAME* aFr
for( size_t i = 0; i < wxSTC_STYLE_MAX; ++i )
m_textEditor->StyleSetFont( i, fixedFont );
m_compileButton->SetBitmap( KiBitmap( reload_xpm ) );
m_textEditor->Bind( wxEVT_STC_CHARADDED, &PANEL_SETUP_RULES::onScintillaCharAdded, this );
m_textEditor->Bind( wxEVT_STC_AUTOCOMP_CHAR_DELETED, &PANEL_SETUP_RULES::onScintillaCharAdded, this );
}
@ -224,6 +228,49 @@ void PANEL_SETUP_RULES::onScintillaCharAdded( wxStyledTextEvent &aEvent )
}
void PANEL_SETUP_RULES::OnCompile( wxCommandEvent& event )
{
m_errorsReport->Clear();
try
{
std::vector<DRC_RULE*> dummyRules;
DRC_RULES_PARSER parser( m_frame->GetBoard(), m_textEditor->GetText(), _( "DRC rules" ) );
parser.Parse( dummyRules, m_errorsReport );
}
catch( PARSE_ERROR& pe )
{
m_Parent->SetError( pe.What(), this, m_textEditor, pe.lineNumber, pe.byteIndex );
}
m_errorsReport->Flush();
}
void PANEL_SETUP_RULES::OnErrorLinkClicked( wxHtmlLinkEvent& event )
{
wxString link = event.GetLinkInfo().GetHref();
wxArrayString parts;
int line = 0, offset = 0;
wxStringSplit( link, parts, ':' );
if( parts.size() > 1 )
{
line = (int) strtol( parts[0], nullptr, 10 );
offset = (int) strtol( parts[1], nullptr, 10 );
}
int pos = m_textEditor->PositionFromLine( line - 1 ) + ( offset - 1 );
m_textEditor->GotoPos( pos );
m_textEditor->SetFocus();
}
bool PANEL_SETUP_RULES::TransferDataToWindow()
{
wxString rulesFilepath = m_frame->Prj().AbsolutePath( "drc-rules" );
@ -249,7 +296,7 @@ bool PANEL_SETUP_RULES::TransferDataFromWindow()
DRC_RULES_PARSER parser( m_frame->GetBoard(), m_textEditor->GetText(), _( "DRC rules" ) );
parser.Parse( dummyRules );
parser.Parse( dummyRules, m_errorsReport );
}
catch( PARSE_ERROR& pe )
{

View File

@ -49,6 +49,8 @@ private:
void onScintillaCharAdded( wxStyledTextEvent &aEvent );
void OnSyntaxHelp( wxHyperlinkEvent& aEvent ) override;
void OnCompile( wxCommandEvent& event );
void OnErrorLinkClicked( wxHtmlLinkEvent& event ) override;
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;

View File

@ -5,6 +5,8 @@
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "wx_html_report_box.h"
#include "panel_setup_rules_base.h"
///////////////////////////////////////////////////////////////////////////
@ -64,7 +66,21 @@ PANEL_SETUP_RULES_BASE::PANEL_SETUP_RULES_BASE( wxWindow* parent, wxWindowID id,
m_textEditor->MarkerDefine( wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_EMPTY );
m_textEditor->SetSelBackground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) );
m_textEditor->SetSelForeground( true, wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) );
m_topMargin->Add( m_textEditor, 1, wxEXPAND | wxALL, 5 );
m_topMargin->Add( m_textEditor, 3, wxEXPAND | wxALL, 5 );
wxBoxSizer* bSizer5;
bSizer5 = new wxBoxSizer( wxHORIZONTAL );
m_compileButton = new wxBitmapButton( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( 40,40 ), wxBU_AUTODRAW|0 );
bSizer5->Add( m_compileButton, 0, wxALL, 3 );
m_errorsReport = new WX_HTML_REPORT_BOX( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO );
m_errorsReport->SetMinSize( wxSize( 400,60 ) );
bSizer5->Add( m_errorsReport, 1, wxALL|wxEXPAND, 5 );
m_topMargin->Add( bSizer5, 1, wxEXPAND, 5 );
m_leftMargin->Add( m_topMargin, 1, wxEXPAND|wxRIGHT|wxLEFT, 10 );
@ -79,11 +95,15 @@ PANEL_SETUP_RULES_BASE::PANEL_SETUP_RULES_BASE( wxWindow* parent, wxWindowID id,
// Connect Events
m_syntaxHelp->Connect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( PANEL_SETUP_RULES_BASE::OnSyntaxHelp ), NULL, this );
m_compileButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SETUP_RULES_BASE::OnCompile ), NULL, this );
m_errorsReport->Connect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( PANEL_SETUP_RULES_BASE::OnErrorLinkClicked ), NULL, this );
}
PANEL_SETUP_RULES_BASE::~PANEL_SETUP_RULES_BASE()
{
// Disconnect Events
m_syntaxHelp->Disconnect( wxEVT_COMMAND_HYPERLINK, wxHyperlinkEventHandler( PANEL_SETUP_RULES_BASE::OnSyntaxHelp ), NULL, this );
m_compileButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_SETUP_RULES_BASE::OnCompile ), NULL, this );
m_errorsReport->Disconnect( wxEVT_COMMAND_HTML_LINK_CLICKED, wxHtmlLinkEventHandler( PANEL_SETUP_RULES_BASE::OnErrorLinkClicked ), NULL, this );
}

View File

@ -221,7 +221,7 @@
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND | wxALL</property>
<property name="proportion">1</property>
<property name="proportion">3</property>
<object class="wxStyledTextCtrl" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
@ -284,6 +284,149 @@
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer5</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">3</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxBitmapButton" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">MyButton</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_compileButton</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size">40,40</property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnCompile</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxHtmlWindow" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">400,60</property>
<property name="moveable">1</property>
<property name="name">m_errorsReport</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxHW_SCROLLBAR_AUTO</property>
<property name="subclass">WX_HTML_REPORT_BOX; wx_html_report_box.h; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnHtmlLinkClicked">OnErrorLinkClicked</event>
</object>
</object>
</object>
</object>
</object>
</object>
</object>

View File

@ -10,6 +10,8 @@
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
class WX_HTML_REPORT_BOX;
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
@ -19,6 +21,12 @@
#include <wx/hyperlink.h>
#include <wx/sizer.h>
#include <wx/stc/stc.h>
#include <wx/bmpbuttn.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/button.h>
#include <wx/html/htmlwin.h>
#include <wx/panel.h>
///////////////////////////////////////////////////////////////////////////
@ -38,9 +46,13 @@ class PANEL_SETUP_RULES_BASE : public wxPanel
wxStaticText* m_title;
wxHyperlinkCtrl* m_syntaxHelp;
wxStyledTextCtrl* m_textEditor;
wxBitmapButton* m_compileButton;
WX_HTML_REPORT_BOX* m_errorsReport;
// Virtual event handlers, overide them in your derived class
virtual void OnSyntaxHelp( wxHyperlinkEvent& event ) { event.Skip(); }
virtual void OnCompile( wxCommandEvent& event ) { event.Skip(); }
virtual void OnErrorLinkClicked( wxHtmlLinkEvent& event ) { event.Skip(); }
public:

View File

@ -60,7 +60,7 @@
#include <drc/drc_textvar_tester.h>
#include <drc/footprint_tester.h>
#include <dialogs/panel_setup_rules.h>
#include <reporter.h>
DRC::DRC() :
PCB_TOOL_BASE( "pcbnew.DRCTool" ),
@ -196,7 +196,7 @@ bool DRC::LoadRules()
try
{
DRC_RULES_PARSER parser( m_pcb, fp, rulesFilepath );
parser.Parse( m_rules );
parser.Parse( m_rules, &NULL_REPORTER::GetInstance() );
}
catch( PARSE_ERROR& pe )
{

View File

@ -29,53 +29,6 @@
#include <pcb_expr_evaluator.h>
/*
* Rule tokens:
* disallow
* constraint
* condition
*
* Disallow types:
* track
* via
* micro_via
* blind_via
* pad
* zone
* text
* graphic
* hole
*
* Constraint types:
* clearance
* annulus_width
* track_width
* hole
*
*
* (rule "HV"
* (constraint clearance (min 200))
* (condition "A.Netclass == 'HV' || B.Netclass == 'HV'")
* )
*
* (rule "HV_external"
* (constraint clearance (min 400))
* (condition "(A.Netclass == 'HV' && (A.onLayer('F.Cu') || A.onLayer('B.Cu'))
* || (B.Netclass == 'HV' && (B.onLayer('F.Cu') || B.onLayer('B.Cu'))")
* )
*
* (rule "HV2HV" (constraint clearance (min 200)))
* (rule "HV2HV_external" (constraint clearance (min 500)))
* (rule "pad2padHV" (constraint clearance (min 500)))
*
* (rule "signal" (constraint clearance (min 20)))
* (rule "neckdown" (constraint clearance (min 15)))
*
* (rule "disallowMicrovias" (disallow micro_via))
*
*
*/
DRC_RULE* GetRule( const BOARD_ITEM* aItem, const BOARD_ITEM* bItem, int aConstraint )
{
BOARD* board = aItem->GetBoard();
@ -131,9 +84,9 @@ bool DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM
}
bool DRC_RULE_CONDITION::Compile()
bool DRC_RULE_CONDITION::Compile( REPORTER* aReporter, int aSourceLine, int aSourceOffset )
{
PCB_EXPR_COMPILER compiler;
PCB_EXPR_COMPILER compiler( aReporter, aSourceLine, aSourceOffset );
if (!m_ucode)
m_ucode = new PCB_EXPR_UCODE;
@ -145,13 +98,7 @@ bool DRC_RULE_CONDITION::Compile()
if( ok )
return true;
m_compileError = compiler.GetErrorStatus();
return false;
}
LIBEVAL::ERROR_STATUS DRC_RULE_CONDITION::GetCompilationError()
{
return m_compileError;
}

View File

@ -85,8 +85,7 @@ public:
~DRC_RULE_CONDITION();
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB );
bool Compile();
LIBEVAL::ERROR_STATUS GetCompilationError();
bool Compile( REPORTER* aReporter, int aSourceLine, int aSourceOffset );
public:
LSET m_LayerCondition;
@ -94,7 +93,6 @@ public:
wxString m_TargetRuleName;
private:
LIBEVAL::ERROR_STATUS m_compileError;
PCB_EXPR_UCODE* m_ucode;
};

View File

@ -23,11 +23,13 @@
#include <fctsys.h>
#include <drc/drc_rule_parser.h>
#include <drc_rules_lexer.h>
#include <class_board.h>
#include <class_board_item.h>
#include <drc/drc_rule_parser.h>
#include <drc_rules_lexer.h>
#include <pcb_expr_evaluator.h>
#include <reporter.h>
using namespace DRCRULE_T;
@ -37,7 +39,8 @@ DRC_RULES_PARSER::DRC_RULES_PARSER( BOARD* aBoard, const wxString& aSource,
DRC_RULES_LEXER( aSource.ToStdString(), aSourceDescr ),
m_board( aBoard ),
m_requiredVersion( 0 ),
m_tooRecent( false )
m_tooRecent( false ),
m_reporter( nullptr )
{
}
@ -46,33 +49,95 @@ DRC_RULES_PARSER::DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxString&
DRC_RULES_LEXER( aFile, aFilename ),
m_board( aBoard ),
m_requiredVersion( 0 ),
m_tooRecent( false )
m_tooRecent( false ),
m_reporter( nullptr )
{
}
void DRC_RULES_PARSER::Parse( std::vector<DRC_RULE*>& aRules )
void DRC_RULES_PARSER::reportError( const wxString& aMessage )
{
wxString rest;
wxString first = aMessage.BeforeFirst( '|', &rest );
wxString msg = wxString::Format( _( "ERROR: <a href='%d:%d'>%s</a>%s" ),
CurLineNumber(),
CurOffset(),
first,
rest );
m_reporter->Report( msg, RPT_SEVERITY_ERROR );
}
void DRC_RULES_PARSER::parseUnknown()
{
int depth = 1;
for( T token = NextTok(); token != T_EOF; token = NextTok() )
{
if( token == T_LEFT )
depth++;
if( token == T_RIGHT )
{
if( --depth == 0 )
break;
}
}
}
void DRC_RULES_PARSER::Parse( std::vector<DRC_RULE*>& aRules, REPORTER* aReporter )
{
bool haveVersion = false;
wxString msg;
m_reporter = aReporter;
for( T token = NextTok(); token != T_EOF; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
reportError( _( "Missing '('." ) );
token = NextTok();
if( !haveVersion && token != T_version )
Expecting( "version" );
{
reportError( _( "Missing version statement." ) );
haveVersion = true; // don't keep on reporting it
}
switch( token )
{
case T_version:
NeedNUMBER( "version" );
haveVersion = true;
token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing version number." ) );
break;
}
if( (int) token == DSN_NUMBER )
{
m_requiredVersion = (int)strtol( CurText(), NULL, 10 );
m_tooRecent = ( m_requiredVersion > DRC_RULE_FILE_VERSION );
haveVersion = true;
NeedRIGHT();
token = NextTok();
}
else
{
msg.Printf( _( "Unrecognized item '%s'.| Expected version number" ), FromUTF8() );
reportError( msg );
}
if( (int) token != DSN_RIGHT )
{
msg.Printf( _( "Unrecognized item '%s'." ), FromUTF8() );
reportError( msg );
parseUnknown();
}
break;
case T_rule:
@ -80,9 +145,13 @@ void DRC_RULES_PARSER::Parse( std::vector<DRC_RULE*>& aRules )
break;
default:
Expecting( "rule" );
msg.Printf( _( "Unrecognized item '%s'.| Expected 'rule' or 'version'." ), FromUTF8() );
reportError( msg );
parseUnknown();
}
}
m_reporter = nullptr;
}
@ -90,23 +159,33 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
{
DRC_RULE* rule = new DRC_RULE();
T token = NextTok();
wxString msg;
if( !IsSymbol( token ) )
Expecting( "rule name" );
reportError( _( "Missing rule name." ) );
rule->m_Name = FromUTF8();
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
reportError( _( "Missing '('." ) );
token = NextTok();
switch( token )
{
case T_disallow:
switch( NextTok() )
token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing disallowed type.| Expected 'track', 'via', 'micro_via', "
"'blind_via', 'pad', 'zone', 'text', 'graphic' or 'hole'." ) );
break;
}
switch( token )
{
case T_track: rule->m_DisallowFlags |= DISALLOW_TRACKS; break;
case T_via: rule->m_DisallowFlags |= DISALLOW_VIAS; break;
@ -118,12 +197,21 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
case T_graphic: rule->m_DisallowFlags |= DISALLOW_GRAPHICS; break;
case T_hole: rule->m_DisallowFlags |= DISALLOW_HOLES; break;
case T_footprint: rule->m_DisallowFlags |= DISALLOW_FOOTPRINTS; break;
default: Expecting( "track, via, micro_via, blind_via, pad, zone, text, "
"graphic, or hole" );
default:
msg.Printf( _( "Unrecognized item '%s'.| Expected 'track', 'via', 'micro_via', "
"'blind_via', 'pad', 'zone', 'text', 'graphic' or 'hole'." ),
FromUTF8() );
reportError( msg );
}
rule->m_ConstraintFlags = DISALLOW_CONSTRAINT;
NeedRIGHT();
if( (int) NextTok() != DSN_RIGHT )
{
reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
parseUnknown();
}
break;
case T_constraint:
@ -131,17 +219,32 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
break;
case T_condition:
NeedSYMBOL();
rule->m_Condition.m_Expression = FromUTF8();
token = NextTok();
if( !rule->m_Condition.Compile() )
if( (int) token == DSN_RIGHT )
{
LIBEVAL::ERROR_STATUS error = rule->m_Condition.GetCompilationError();
THROW_PARSE_ERROR( error.message, CurSource(), CurLine(), CurLineNumber(),
CurOffset() + error.srcPos );
reportError( _( "Missing condition expression." ) );
break;
}
if( IsSymbol( token ) )
{
rule->m_Condition.m_Expression = FromUTF8();
rule->m_Condition.Compile( m_reporter, CurLineNumber(), CurOffset() );
}
else
{
msg.Printf( _( "Unrecognized item '%s'.| Expected quoted expression." ),
FromUTF8() );
reportError( msg );
}
if( (int) NextTok() != DSN_RIGHT )
{
reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
parseUnknown();
}
NeedRIGHT();
break;
case T_layer:
@ -149,7 +252,11 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
break;
default:
Expecting( "disallow, constraint or condition" );
msg.Printf( _( "Unrecognized item '%s'.| Expected 'constraint', 'condition' or "
"'disallow'." ),
FromUTF8() );
reportError( msg );
parseUnknown();
}
}
@ -160,16 +267,30 @@ DRC_RULE* DRC_RULES_PARSER::parseDRC_RULE()
void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
{
T token;
int constraintType;
int constraintType = 0;
int value;
wxString msg;
switch( NextTok() )
token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing constraint type.| Expected 'clearance', 'track_width', "
"'annulus_width' or 'hole'." ) );
return;
}
switch( token )
{
case T_clearance: constraintType = CLEARANCE_CONSTRAINT; break;
case T_track_width: constraintType = TRACK_CONSTRAINT; break;
case T_annulus_width: constraintType = ANNULUS_CONSTRAINT; break;
case T_hole: constraintType = HOLE_CONSTRAINT; break;
default: Expecting( "clearance, track_width, annulus_width, or hole" ); return;
default:
msg.Printf( _( "Unrecognized item '%s'.| Expected 'clearance', 'track_width', "
"'annulus_width' or 'hole'." ),
FromUTF8() );
reportError( msg );
}
aRule->m_ConstraintFlags |= constraintType;
@ -177,14 +298,21 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
reportError( _( "Missing '('." ) );
token = NextTok();
switch( token )
{
case T_min:
NextTok();
token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing min value." ) );
break;
}
parseValueWithUnits( FromUTF8(), value );
switch( constraintType )
@ -195,39 +323,69 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
case HOLE_CONSTRAINT: aRule->m_MinHole = value; break;
}
NeedRIGHT();
if( (int) NextTok() != DSN_RIGHT )
{
reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
parseUnknown();
}
break;
case T_max:
NextTok();
token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing max value." ) );
break;
}
parseValueWithUnits( FromUTF8(), value );
switch( constraintType )
{
case CLEARANCE_CONSTRAINT: aRule->m_Clearance.Max = value; break;
case TRACK_CONSTRAINT: aRule->m_TrackConstraint.Max = value; break;
default: Expecting( "min" );
}
NeedRIGHT();
if( (int) NextTok() != DSN_RIGHT )
{
reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
parseUnknown();
}
break;
case T_opt:
NextTok();
token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing opt value." ) );
break;
}
parseValueWithUnits( FromUTF8(), value );
switch( constraintType )
{
case CLEARANCE_CONSTRAINT: aRule->m_Clearance.Opt = value; break;
case TRACK_CONSTRAINT: aRule->m_TrackConstraint.Opt = value; break;
default: Expecting( "min" );
}
NeedRIGHT();
if( (int) NextTok() != DSN_RIGHT )
{
reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
parseUnknown();
}
break;
default:
Expecting( "allow or constraint" );
msg.Printf( _( "Unrecognized item '%s'.| Expected 'min', 'max' or 'opt'." ),
FromUTF8() );
reportError( msg );
parseUnknown();
}
}
}
@ -235,17 +393,9 @@ void DRC_RULES_PARSER::parseConstraint( DRC_RULE* aRule )
void DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult )
{
PCB_EXPR_EVALUATOR evaluator;
bool ok = evaluator.Evaluate( aExpr );
if( !ok )
{
LIBEVAL::ERROR_STATUS error = evaluator.GetErrorStatus();
THROW_PARSE_ERROR( error.message, CurSource(), CurLine(), CurLineNumber(),
CurOffset() + error.srcPos );
}
PCB_EXPR_EVALUATOR evaluator( m_reporter, CurLineNumber(), CurOffset() );
evaluator.Evaluate( aExpr );
aResult = evaluator.Result();
}
@ -253,13 +403,18 @@ void DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult
LSET DRC_RULES_PARSER::parseLayer()
{
LSET retVal;
int tok = NextTok();
int token = NextTok();
if( tok == T_outer )
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing layer name or type." ) );
return LSET::AllCuMask();
}
else if( token == T_outer )
{
retVal = LSET::ExternalCuMask();
}
else if( tok == T_inner )
else if( token == T_inner )
{
retVal = LSET::InternalCuMask();
}
@ -269,14 +424,16 @@ LSET DRC_RULES_PARSER::parseLayer()
PCB_LAYER_ID layer = ENUM_MAP<PCB_LAYER_ID>::Instance().ToEnum( layerName );
if( layer == UNDEFINED_LAYER )
{
wxString msg = wxString::Format( _( "Unrecognized layer '%s' " ), layerName );
THROW_PARSE_ERROR( msg, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
}
reportError( wxString::Format( _( "Unrecognized layer '%s' " ), layerName ) );
retVal.set( layer );
}
NeedRIGHT();
if( (int) NextTok() != DSN_RIGHT )
{
reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
parseUnknown();
}
return retVal;
}

View File

@ -43,7 +43,7 @@ public:
DRC_RULES_PARSER( BOARD* aBoard, const wxString& aSource, const wxString& aSourceDescr );
DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxString& aFilename );
void Parse( std::vector<DRC_RULE*>& aRules );
void Parse( std::vector<DRC_RULE*>& aRules, REPORTER* aReporter );
private:
DRC_RULE* parseDRC_RULE();
@ -51,11 +51,15 @@ private:
void parseConstraint( DRC_RULE* aRule );
void parseValueWithUnits( const wxString& aExpr, int& aResult );
LSET parseLayer();
void parseUnknown();
void reportError( const wxString& aMessage );
private:
BOARD* m_board;
int m_requiredVersion;
bool m_tooRecent;
REPORTER* m_reporter;
};
#endif // DRC_RULE_PARSER_H

View File

@ -25,9 +25,9 @@
#include <cstdio>
#include <boost/algorithm/string/case_conv.hpp>
#include <memory>
#include "class_board.h"
#include "pcb_expr_evaluator.h"
#include <reporter.h>
#include <class_board.h>
#include <pcb_expr_evaluator.h>
static void onLayer( LIBEVAL::CONTEXT* aCtx, void *self )
@ -187,8 +187,7 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx )
}
LIBEVAL::UCODE::FUNC_PTR PCB_EXPR_UCODE::createFuncCall( LIBEVAL::COMPILER* aCompiler,
const char* aName )
LIBEVAL::UCODE::FUNC_PTR PCB_EXPR_UCODE::CreateFuncCall( const char* aName )
{
PCB_EXPR_BUILTIN_FUNCTIONS& registry = PCB_EXPR_BUILTIN_FUNCTIONS::Instance();
@ -199,8 +198,7 @@ LIBEVAL::UCODE::FUNC_PTR PCB_EXPR_UCODE::createFuncCall( LIBEVAL::COMPILER* aCom
}
LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler, const char* aVar,
const char* aField )
LIBEVAL::VAR_REF* PCB_EXPR_UCODE::CreateVarRef( const char* aVar, const char* aField )
{
PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
PCB_EXPR_VAR_REF* vref = nullptr;
@ -215,7 +213,6 @@ LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler, co
}
else
{
aCompiler->ReportError( "var" );
return vref;
}
@ -251,16 +248,14 @@ LIBEVAL::VAR_REF* PCB_EXPR_UCODE::createVarRef( LIBEVAL::COMPILER *aCompiler, co
}
else
{
(void) 0; // should we do anything here?
//msg.Printf("Unrecognized type for property '%s'", field.c_str() );
//aCompiler->ReportError( (const char*) msg.c_str() );
wxFAIL_MSG( "PCB_EXPR_UCODE::createVarRef: Unknown property type." );
}
}
}
}
if( vref->GetType() == LIBEVAL::VT_UNDEFINED )
aCompiler->ReportError( "field" );
vref->SetType( LIBEVAL::VT_PARSE_ERROR );
return vref;
}
@ -295,13 +290,15 @@ public:
};
PCB_EXPR_COMPILER::PCB_EXPR_COMPILER()
PCB_EXPR_COMPILER::PCB_EXPR_COMPILER( REPORTER* aReporter, int aSourceLine, int aSourcePos ) :
COMPILER( aReporter, aSourceLine, aSourcePos )
{
m_unitResolver = std::make_unique<PCB_UNIT_RESOLVER>();
}
PCB_EXPR_EVALUATOR::PCB_EXPR_EVALUATOR()
PCB_EXPR_EVALUATOR::PCB_EXPR_EVALUATOR( REPORTER* aReporter, int aSourceLine, int aSourceOffset ) :
m_compiler( aReporter, aSourceLine, aSourceOffset )
{
m_result = 0;
}
@ -316,15 +313,10 @@ bool PCB_EXPR_EVALUATOR::Evaluate( const wxString& aExpr )
PCB_EXPR_UCODE ucode;
LIBEVAL::CONTEXT preflightContext;
if( !m_compiler.Compile( aExpr.ToUTF8().data(), &ucode, &preflightContext ) )
{
m_errorStatus = m_compiler.GetErrorStatus();
return false;
}
m_compiler.Compile( aExpr.ToUTF8().data(), &ucode, &preflightContext );
// fixme: handle error conditions
LIBEVAL::CONTEXT ctx;
LIBEVAL::VALUE* result = ucode.Run( &ctx );
LIBEVAL::CONTEXT evaluationContext;
LIBEVAL::VALUE* result = ucode.Run( &evaluationContext );
if( result->GetType() == LIBEVAL::VT_NUMERIC )
m_result = KiROUND( result->AsDouble() );

View File

@ -43,10 +43,9 @@ public:
PCB_EXPR_UCODE() {};
virtual ~PCB_EXPR_UCODE() {};
virtual LIBEVAL::VAR_REF* createVarRef( LIBEVAL::COMPILER *aCompiler, const char* aVar,
const char* aField ) override;
virtual LIBEVAL::VAR_REF* CreateVarRef( const char* aVar, const char* aField ) override;
virtual FUNC_PTR createFuncCall( LIBEVAL::COMPILER* aCompiler, const char* aName ) override;
virtual FUNC_PTR CreateFuncCall( const char* aName ) override;
};
@ -83,7 +82,7 @@ public:
m_type( LIBEVAL::VT_UNDEFINED ),
m_isEnum( false )
{
//printf("*** createVarRef %p %d\n", this, aItemIndex );
//printf("*** CreateVarRef %p %d\n", this, aItemIndex );
}
void SetIsEnum( bool s ) { m_isEnum = s; }
@ -142,28 +141,24 @@ private:
class PCB_EXPR_COMPILER : public LIBEVAL::COMPILER
{
public:
PCB_EXPR_COMPILER();
PCB_EXPR_COMPILER( REPORTER* aReporter, int aSourceLine, int aSourcePos );
};
class PCB_EXPR_EVALUATOR
{
public:
PCB_EXPR_EVALUATOR();
PCB_EXPR_EVALUATOR( REPORTER* aReporter, int aSourceLine, int aSourceOffset );
~PCB_EXPR_EVALUATOR();
bool Evaluate( const wxString& aExpr );
int Result() const { return m_result; }
LIBEVAL::ERROR_STATUS GetErrorStatus() { return m_errorStatus; }
private:
int m_result;
PCB_EXPR_COMPILER m_compiler;
PCB_EXPR_UCODE m_ucode;
LIBEVAL::ERROR_STATUS m_errorStatus;
};
#endif

View File

@ -78,7 +78,7 @@ bool test::DRC_ENGINE::LoadRules( wxFileName aPath )
try
{
DRC_RULES_PARSER parser( m_board, fp, aPath.GetFullPath() );
parser.Parse( m_ruleConditions, m_rules );
parser.Parse( m_ruleConditions, m_rules, &NULL_REPORTER::GetInstance() );
}
catch( PARSE_ERROR& pe )
{
@ -175,7 +175,7 @@ bool test::DRC_ENGINE::CompileRules()
{
rcons->conditions.push_back( condition );
bool compileOk = condition->Compile();
bool compileOk = condition->Compile( &NULL_REPORTER::GetInstance() );
ReportAux( wxString::Format( " |- condition: '%s' compile: %s", condition->m_TargetRuleName, compileOk ? "OK" : "ERROR") );

View File

@ -64,9 +64,9 @@ bool test::DRC_RULE_CONDITION::EvaluateFor( const BOARD_ITEM* aItemA, const BOAR
}
bool test::DRC_RULE_CONDITION::Compile()
bool test::DRC_RULE_CONDITION::Compile( REPORTER* aReporter, int aSourceLine, int aSourceOffset )
{
PCB_EXPR_COMPILER compiler;
PCB_EXPR_COMPILER compiler( aReporter, aSourceLine, aSourceOffset );
if (!m_ucode)
m_ucode = new PCB_EXPR_UCODE;
@ -74,19 +74,7 @@ bool test::DRC_RULE_CONDITION::Compile()
LIBEVAL::CONTEXT preflightContext;
bool ok = compiler.Compile( m_Expression.ToUTF8().data(), m_ucode, &preflightContext );
if( ok )
return true;
m_compileError = compiler.GetErrorStatus();
printf( "Fail: %s (pos: %d)\n", (const char *) m_compileError.message.c_str(), m_compileError.srcPos );
return false;
return ok;
}
LIBEVAL::ERROR_STATUS test::DRC_RULE_CONDITION::GetCompilationError()
{
return m_compileError;
}

View File

@ -125,6 +125,7 @@ public:
DRC_CONSTRAINT m_Constraint;
};
class DRC_RULE_CONDITION
{
public:
@ -132,15 +133,14 @@ public:
~DRC_RULE_CONDITION();
bool EvaluateFor( const BOARD_ITEM* aItemA, const BOARD_ITEM* aItemB );
bool Compile();
LIBEVAL::ERROR_STATUS GetCompilationError();
bool Compile( REPORTER* aReporter, int aSourceLine = 0, int aSourceOffset = 0 );
public:
LSET m_LayerCondition;
wxString m_Expression;
wxString m_TargetRuleName;
private:
LIBEVAL::ERROR_STATUS m_compileError;
PCB_EXPR_UCODE* m_ucode;
};

View File

@ -22,6 +22,7 @@
*/
#include <fctsys.h>
#include <class_board.h>
#include <class_board_item.h>
@ -29,11 +30,8 @@
#include <drc_proto/drc_rule_parser.h>
#include <drc_proto/drc_rules_lexer.h>
#include <drc_proto/drc_engine.h> // drc_dbg
#include <fctsys.h>
#include <pcb_expr_evaluator.h>
#include <reporter.h>
using namespace DRCRULEPROTO_T;
@ -43,37 +41,94 @@ test::DRC_RULES_PARSER::DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxSt
m_requiredVersion( 0 ),
m_tooRecent( false )
{
for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
}
void test::DRC_RULES_PARSER::reportError( const wxString& aMessage )
{
wxString rest;
wxString first = aMessage.BeforeFirst( '|', &rest );
wxString msg = wxString::Format( _( "ERROR: <a href='%d:%d'>%s</a>%s" ),
CurLineNumber(),
CurOffset(),
first,
rest );
m_reporter->Report( msg, RPT_SEVERITY_ERROR );
}
void test::DRC_RULES_PARSER::parseUnknown()
{
int depth = 1;
for( T token = NextTok(); token != T_EOF; token = NextTok() )
{
std::string untranslated = TO_UTF8( wxString( LSET::Name( PCB_LAYER_ID( layer ) ) ) );
m_layerMap[untranslated] = PCB_LAYER_ID( layer );
if( token == T_LEFT )
depth++;
if( token == T_RIGHT )
{
if( --depth == 0 )
break;
}
}
}
void test::DRC_RULES_PARSER::Parse(
std::vector<test::DRC_RULE_CONDITION*>& aConditions, std::vector<test::DRC_RULE*>& aRules )
void test::DRC_RULES_PARSER::Parse( std::vector<test::DRC_RULE_CONDITION*>& aConditions,
std::vector<test::DRC_RULE*>& aRules,
REPORTER* aReporter )
{
bool haveVersion = false;
wxString msg;
m_reporter = aReporter;
for( T token = NextTok(); token != T_EOF; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
reportError( _( "Missing '('." ) );
token = NextTok();
if( !haveVersion && token != T_version )
Expecting( "version" );
{
reportError( _( "Missing version statement." ) );
haveVersion = true; // don't keep on reporting it
}
switch( token )
{
case T_version:
NeedNUMBER( "version" );
m_requiredVersion = (int) strtol( CurText(), NULL, 10 );
m_tooRecent = ( m_requiredVersion > DRC_RULE_FILE_VERSION );
haveVersion = true;
NeedRIGHT();
token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing version number." ) );
break;
}
if( (int) token == DSN_NUMBER )
{
m_requiredVersion = (int)strtol( CurText(), NULL, 10 );
m_tooRecent = ( m_requiredVersion > DRC_RULE_FILE_VERSION );
token = NextTok();
}
else
{
msg.Printf( _( "Unrecognized item '%s'.| Expected version number" ), FromUTF8() );
reportError( msg );
}
if( (int) token != DSN_RIGHT )
{
msg.Printf( _( "Unrecognized item '%s'." ), FromUTF8() );
reportError( msg );
parseUnknown();
}
break;
case T_condition:
@ -89,7 +144,10 @@ void test::DRC_RULES_PARSER::Parse(
}
default:
Expecting( "condition or rule" );
msg.Printf( _( "Unrecognized item '%s'.| Expected 'rule', 'condition' or 'version'." ),
FromUTF8() );
reportError( msg );
parseUnknown();
}
}
}
@ -109,6 +167,8 @@ test::DRC_RULE_CONDITION* test::DRC_RULES_PARSER::parseCONDITION()
//printf( "Do token xxx %d '%s'\n", token, (const char*) FromUTF8().c_str() );
// TODO: Needs updating to report errors through REPORTER
switch( token )
{
case T_expression:
@ -139,16 +199,17 @@ test::DRC_RULE* test::DRC_RULES_PARSER::parseRULE()
DRC_RULE* rule = new DRC_RULE();
T token = NextTok();
int value;
wxString msg;
if( !IsSymbol( token ) )
Expecting( "rule name" );
reportError( _( "Missing rule name." ) );
rule->m_Name = FromUTF8();
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
reportError( _( "Missing '('." ) );
token = NextTok();
@ -157,26 +218,70 @@ test::DRC_RULE* test::DRC_RULES_PARSER::parseRULE()
switch( token )
{
case T_type:
// TODO: I assume this won't be in the final impl and so doesn't need converting
// to new error reporting framework?
NeedSYMBOL();
rule->m_TestProviderName = FromUTF8();
break;
case T_min:
NeedSYMBOL();
token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing min value." ) );
break;
}
parseValueWithUnits( FromUTF8(), value );
rule->m_Constraint.m_Value.SetMin( value );
if( (int) NextTok() != DSN_RIGHT )
{
reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
parseUnknown();
}
break;
case T_opt:
NeedSYMBOL();
token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing opt value." ) );
break;
}
parseValueWithUnits( FromUTF8(), value );
rule->m_Constraint.m_Value.SetOpt( value );
if( (int) NextTok() != DSN_RIGHT )
{
reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
parseUnknown();
}
break;
case T_max:
NeedSYMBOL();
token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing max value." ) );
break;
}
parseValueWithUnits( FromUTF8(), value );
rule->m_Constraint.m_Value.SetMax( value );
if( (int) NextTok() != DSN_RIGHT )
{
reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
parseUnknown();
}
break;
case T_allow:
@ -209,7 +314,12 @@ test::DRC_RULE* test::DRC_RULES_PARSER::parseRULE()
default:
Expecting( "type, min, opt, max, allow, enable, priority or severity" );
// TODO: reconcile
//Expecting( "type, min, opt, max, allow, enable, priority or severity" );
msg.Printf( _( "Unrecognized item '%s'.| Expected 'min', 'max' or 'opt'." ),
FromUTF8() );
reportError( msg );
parseUnknown();
break;
}
@ -222,16 +332,47 @@ test::DRC_RULE* test::DRC_RULES_PARSER::parseRULE()
void test::DRC_RULES_PARSER::parseValueWithUnits( const wxString& aExpr, int& aResult )
{
PCB_EXPR_EVALUATOR evaluator;
bool ok = evaluator.Evaluate( aExpr );
if( !ok )
{
LIBEVAL::ERROR_STATUS error = evaluator.GetErrorStatus();
THROW_PARSE_ERROR( error.message, CurSource(), CurLine(), CurLineNumber(),
CurOffset() + error.srcPos );
}
PCB_EXPR_EVALUATOR evaluator( m_reporter, CurLineNumber(), CurOffset() );
evaluator.Evaluate( aExpr );
aResult = evaluator.Result();
};
LSET test::DRC_RULES_PARSER::parseLayer()
{
LSET retVal;
int token = NextTok();
if( (int) token == DSN_RIGHT )
{
reportError( _( "Missing layer name or type." ) );
return LSET::AllCuMask();
}
else if( token == T_outer )
{
retVal = LSET::ExternalCuMask();
}
else if( token == T_inner )
{
retVal = LSET::InternalCuMask();
}
else
{
wxString layerName = FromUTF8();
PCB_LAYER_ID layer = ENUM_MAP<PCB_LAYER_ID>::Instance().ToEnum( layerName );
if( layer == UNDEFINED_LAYER )
reportError( wxString::Format( _( "Unrecognized layer '%s' " ), layerName ) );
retVal.set( layer );
}
if( (int) NextTok() != DSN_RIGHT )
{
reportError( wxString::Format( _( "Unrecognized item '%s'." ), FromUTF8() ) );
parseUnknown();
}
return retVal;
}

View File

@ -45,7 +45,8 @@ class DRC_RULES_PARSER : public DRC_RULES_PROTO_LEXER
public:
DRC_RULES_PARSER( BOARD* aBoard, FILE* aFile, const wxString& aFilename );
void Parse( std::vector<DRC_RULE_CONDITION*>& aConditions, std::vector<DRC_RULE*>& aRules );
void Parse( std::vector<DRC_RULE_CONDITION*>& aConditions, std::vector<DRC_RULE*>& aRules,
REPORTER* aReporter );
private:
DRC_RULE_CONDITION* parseCONDITION();
@ -63,7 +64,12 @@ private:
return parseInt();
}
// void parseConstraint( DRC_RULE* aRule );
LSET parseLayer();
void parseUnknown();
void reportError( const wxString& aMessage );
// void parseConstraint( DRC_RULE* aRule );
//int parseValue( DRCRULE_T::T aToken );
private:
@ -71,8 +77,7 @@ private:
BOARD* m_board;
int m_requiredVersion;
bool m_tooRecent;
std::unordered_map<std::string, PCB_LAYER_ID> m_layerMap;
REPORTER* m_reporter;
};
};

View File

@ -1,11 +1,16 @@
clearance
condition
constraint
inner
layer
max
min
name
opt
outer
allow
rule
version
name
priority
expression
enable