1 #/* Verilog.xs -- Verilog Booter  -*- C++ -*-
2 #*********************************************************************
3 #*
4 #* DESCRIPTION: Verilog::Parser Perl XS interface
5 #*
6 #* Author: Wilson Snyder <wsnyder@wsnyder.org>
7 #*
8 #* Code available from: https://www.veripool.org/
9 #*
10 #*********************************************************************
11 #*
12 #* Copyright 2000-2021 by Wilson Snyder.  This program is free software;
13 #* you can redistribute it and/or modify it under the terms of either the GNU
14 #* Lesser General Public License Version 3 or the Perl Artistic License Version 2.0.
15 #*
16 #* This program is distributed in the hope that it will be useful,
17 #* but WITHOUT ANY WARRANTY; without even the implied warranty of
18 #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 #* GNU General Public License for more details.
20 #*
21 #* You should have received a copy of the Perl Artistic License
22 #* along with this module; see the file COPYING.  If not, see
23 #* www.cpan.org
24 #*
25 #***********************************************************************
26 #* Note with C++ XS libraries, the CLASS parameter is implied...
27 #***********************************************************************/
28 
29 /* Mine: */
30 #include "VParse.h"
31 #include "VSymTable.h"
32 #include "VAst.h"
33 #include <cstring>
34 #include <deque>
35 
36 /* Perl */
37 extern "C" {
38 # include "EXTERN.h"
39 # include "perl.h"
40 # include "XSUB.h"
41 }
42 
43 #ifdef open
44 # undef open	/* Perl 64 bit on solaris has a nasty hack that redefines open */
45 #endif
46 
47 // This is a global constant pointer initialized to its own address to
48 // produce a unique address to distinguish hashes (pointers to
49 // struct VParseHashElem) from the strings (character pointers) used by
50 // callbackgen in its variadic parameters for VParserXs::call().
51 static void *hasharray_param = &hasharray_param;
52 
53 class VFileLineParseXs;
54 
55 #//**********************************************************************
56 #// Parseressor derived classes, so we can override the callbacks to call perl.
57 
58 class VParserXs : public VParse {
59 public:
60     SV*		m_self;	// Class called from (the hash, not SV pointing to the hash)
61     VFileLine*	m_cbFilelinep;	///< Last callback's starting point
62     deque<VFileLineParseXs*> m_filelineps;
63 
64     // CALLBACKGEN_H_MEMBERS
65     // CALLBACKGEN_GENERATED_BEGIN - GENERATED AUTOMATICALLY by callbackgen
66     struct {  // Bit packed to help the cache
67         bool m_useCb_attribute:1;
68         bool m_useCb_class:1;
69         bool m_useCb_comment:1;
70         bool m_useCb_contassign:1;
71         bool m_useCb_covergroup:1;
72         bool m_useCb_defparam:1;
73         bool m_useCb_endcell:1;
74         bool m_useCb_endclass:1;
75         bool m_useCb_endgroup:1;
76         bool m_useCb_endinterface:1;
77         bool m_useCb_endmodport:1;
78         bool m_useCb_endmodule:1;
79         bool m_useCb_endpackage:1;
80         bool m_useCb_endparse:1;
81         bool m_useCb_endprogram:1;
82         bool m_useCb_endtaskfunc:1;
83         bool m_useCb_function:1;
84         bool m_useCb_import:1;
85         bool m_useCb_instant:1;
86         bool m_useCb_interface:1;
87         bool m_useCb_keyword:1;
88         bool m_useCb_modport:1;
89         bool m_useCb_module:1;
90         bool m_useCb_number:1;
91         bool m_useCb_operator:1;
92         bool m_useCb_package:1;
93         bool m_useCb_parampin:1;
94         bool m_useCb_pin:1;
95         bool m_useCb_pinselects:1;
96         bool m_useCb_port:1;
97         bool m_useCb_preproc:1;
98         bool m_useCb_program:1;
99         bool m_useCb_string:1;
100         bool m_useCb_symbol:1;
101         bool m_useCb_sysfunc:1;
102         bool m_useCb_task:1;
103         bool m_useCb_var:1;
104     };
105     // CALLBACKGEN_GENERATED_END - GENERATED AUTOMATICALLY by callbackgen
106 
cbFilelinep()107     VFileLine* cbFilelinep() const { return m_cbFilelinep; }
cbFileline(VFileLine * filelinep)108     void cbFileline(VFileLine* filelinep) { m_cbFilelinep = filelinep; }
109 
VParserXs(VFileLine * filelinep,av * symsp,bool sigparser,bool useUnreadback,bool useProtected,bool usePinselects)110     VParserXs(VFileLine* filelinep, av* symsp,
111 	      bool sigparser, bool useUnreadback, bool useProtected, bool usePinselects)
112 	: VParse(filelinep, symsp, sigparser, useUnreadback, useProtected, usePinselects)
113 	, m_cbFilelinep(filelinep)
114 	{ set_cb_use(); }
115     virtual ~VParserXs();
116 
117     // CALLBACKGEN_CB_USE
118     // CALLBACKGEN_GENERATED_BEGIN - GENERATED AUTOMATICALLY by callbackgen
set_cb_use()119     void set_cb_use() {
120        m_useCb_attribute = true;
121        m_useCb_class = true;
122        m_useCb_comment = true;
123        m_useCb_contassign = true;
124        m_useCb_covergroup = true;
125        m_useCb_defparam = true;
126        m_useCb_endcell = true;
127        m_useCb_endclass = true;
128        m_useCb_endgroup = true;
129        m_useCb_endinterface = true;
130        m_useCb_endmodport = true;
131        m_useCb_endmodule = true;
132        m_useCb_endpackage = true;
133        m_useCb_endparse = true;
134        m_useCb_endprogram = true;
135        m_useCb_endtaskfunc = true;
136        m_useCb_function = true;
137        m_useCb_import = true;
138        m_useCb_instant = true;
139        m_useCb_interface = true;
140        m_useCb_keyword = true;
141        m_useCb_modport = true;
142        m_useCb_module = true;
143        m_useCb_number = true;
144        m_useCb_operator = true;
145        m_useCb_package = true;
146        m_useCb_parampin = true;
147        m_useCb_pin = true;
148        m_useCb_pinselects = true;
149        m_useCb_port = true;
150        m_useCb_preproc = true;
151        m_useCb_program = true;
152        m_useCb_string = true;
153        m_useCb_symbol = true;
154        m_useCb_sysfunc = true;
155        m_useCb_task = true;
156        m_useCb_var = true;
157    }
158     // CALLBACKGEN_GENERATED_END - GENERATED AUTOMATICALLY by callbackgen
159     // CALLBACKGEN_H_VIRTUAL
160     // CALLBACKGEN_GENERATED_BEGIN - GENERATED AUTOMATICALLY by callbackgen
161     // Verilog::Parser Callback methods
162     virtual void attributeCb(VFileLine* fl, const string& text);
163     virtual void commentCb(VFileLine* fl, const string& text);
164     virtual void endparseCb(VFileLine* fl, const string& text);
165     virtual void keywordCb(VFileLine* fl, const string& text);
166     virtual void numberCb(VFileLine* fl, const string& text);
167     virtual void operatorCb(VFileLine* fl, const string& text);
168     virtual void preprocCb(VFileLine* fl, const string& text);
169     virtual void stringCb(VFileLine* fl, const string& text);
170     virtual void symbolCb(VFileLine* fl, const string& text);
171     virtual void sysfuncCb(VFileLine* fl, const string& text);
172     // Verilog::SigParser Callback methods
173     virtual void classCb(VFileLine* fl, const string& kwd, const string& name, const string& virt);
174     virtual void contassignCb(VFileLine* fl, const string& kwd, const string& lhs, const string& rhs);
175     virtual void covergroupCb(VFileLine* fl, const string& kwd, const string& name);
176     virtual void defparamCb(VFileLine* fl, const string& kwd, const string& lhs, const string& rhs);
177     virtual void endcellCb(VFileLine* fl, const string& kwd);
178     virtual void endclassCb(VFileLine* fl, const string& kwd);
179     virtual void endgroupCb(VFileLine* fl, const string& kwd);
180     virtual void endinterfaceCb(VFileLine* fl, const string& kwd);
181     virtual void endmodportCb(VFileLine* fl, const string& kwd);
182     virtual void endmoduleCb(VFileLine* fl, const string& kwd);
183     virtual void endpackageCb(VFileLine* fl, const string& kwd);
184     virtual void endprogramCb(VFileLine* fl, const string& kwd);
185     virtual void endtaskfuncCb(VFileLine* fl, const string& kwd);
186     virtual void functionCb(VFileLine* fl, const string& kwd, const string& name, const string& data_type);
187     virtual void importCb(VFileLine* fl, const string& package, const string& id);
188     virtual void instantCb(VFileLine* fl, const string& mod, const string& cell, const string& range);
189     virtual void interfaceCb(VFileLine* fl, const string& kwd, const string& name);
190     virtual void modportCb(VFileLine* fl, const string& kwd, const string& name);
191     virtual void moduleCb(VFileLine* fl, const string& kwd, const string& name, bool, bool celldefine);
192     virtual void packageCb(VFileLine* fl, const string& kwd, const string& name);
193     virtual void parampinCb(VFileLine* fl, const string& name, const string& conn, int index);
194     virtual void pinCb(VFileLine* fl, const string& name, const string& conn, int index);
195     virtual void pinselectsCb(VFileLine* fl, const string& name, unsigned int arraycnt2, unsigned int elemcnt2, const VParseHashElem* conns2, int index);
196     virtual void portCb(VFileLine* fl, const string& name, const string& objof, const string& direction, const string& data_type
197 	, const string& array, int index);
198     virtual void programCb(VFileLine* fl, const string& kwd, const string& name);
199     virtual void taskCb(VFileLine* fl, const string& kwd, const string& name);
200     virtual void varCb(VFileLine* fl, const string& kwd, const string& name, const string& objof, const string& net
201 	, const string& data_type, const string& array, const string& value);
202     // CALLBACKGEN_GENERATED_END - GENERATED AUTOMATICALLY by callbackgen
203 
204     void useCbEna(const char* name, bool flag);
205     void call(string* rtnStrp, int params, const char* method, ...);
206 };
207 
208 class VFileLineParseXs : public VFileLine {
209     VParserXs*	m_vParserp;		// Parser handling the errors
210 
211 public:
VFileLineParseXs(VParserXs * pp)212     VFileLineParseXs(VParserXs* pp) : VFileLine(true), m_vParserp(pp) { if (pp) pushFl(); }
~VFileLineParseXs()213     virtual ~VFileLineParseXs() { }
create(const string & filename,int lineno)214     virtual VFileLine* create(const string& filename, int lineno) {
215 	VFileLineParseXs* filelp = new VFileLineParseXs(m_vParserp);
216 	filelp->init(filename, lineno);
217 	return filelp;
218     }
219     virtual void error(const string& msg);	// Report a error at given location
setParser(VParserXs * pp)220     void setParser(VParserXs* pp) {
221 	m_vParserp=pp;
222 	pushFl(); // The very first construction used pp=NULL, as pp wasn't created yet so make it now
223     }
224     // Record the structure so we can delete it later
pushFl()225     void pushFl() { m_vParserp->m_filelineps.push_back(this); }
226 };
227 
228 #//**********************************************************************
229 #// Overrides error handling virtual functions to invoke callbacks
230 
error(const string & msg)231 void VFileLineParseXs::error(const string& msg) {
232     static string holdmsg; holdmsg = msg;
233     m_vParserp->cbFileline(this);
234     // Call always, not just if callbacks enabled
235     m_vParserp->call(NULL, 1,"error",holdmsg.c_str());
236 }
237 
238 #//**********************************************************************
239 #// Overrides of virtual functions to invoke callbacks
240 
241 #include "Parser_callbackgen.cpp"
242 
243 #//**********************************************************************
244 #// VParserXs functions
245 
~VParserXs()246 VParserXs::~VParserXs() {
247     for (deque<VFileLineParseXs*>::iterator it=m_filelineps.begin(); it!=m_filelineps.end(); ++it) {
248 	delete *it;
249     }
250 }
251 
252 #//**********************************************************************
253 #// General callback invoker
254 
call(string * rtnStrp,int params,const char * method,...)255 void VParserXs::call(
256     string* rtnStrp,	/* If non-null, load return value here */
257     int params,		/* Number of parameters */
258     const char* method,	/* Name of method to call */
259     ...)		/* Arguments to pass to method's @_ */
260 {
261     // Call $perlself->method (passedparam1, parsedparam2)
262     if (debug()) cout << "CALLBACK "<<method<<endl;
263     va_list ap;
264     va_start(ap, method);
265     {
266 	dSP;				/* Initialize stack pointer */
267 	ENTER;				/* everything created after here */
268 	SAVETMPS;			/* ...is a temporary variable. */
269 	PUSHMARK(SP);			/* remember the stack pointer */
270 	SV* selfsv = newRV_inc(m_self);	/* $self-> */
271 	XPUSHs(sv_2mortal(selfsv));
272 
273 	while (params--) {
274 	    char* textp = va_arg(ap, char *);
275 	    if (textp == hasharray_param) {
276 		// First hasharray param defines number of array elements
277 		unsigned int arrcnt = va_arg(ap, unsigned int);
278 		AV* av = newAV();
279 		av_extend(av, arrcnt);
280 
281 		// Second hasharray param defines how many keys are within one hash
282 		unsigned int elemcnt = va_arg(ap, unsigned int);
283 		// Followed by the hash array pointer...
284 		const VParseHashElem* arrp = va_arg(ap, const VParseHashElem*);  // [arrcnt][elemcnt]
285 		for (unsigned int i = 0; i < arrcnt; i++) {
286 		    HV* hv = newHV();
287 		    const VParseHashElem* elemp = arrp + elemcnt*i;
288 		    for (unsigned int j = 0; j < elemcnt; j++) {
289 			if (!elemp[j].keyp)
290 			    continue;
291 			SV* sv;
292 			switch (elemp[j].val_type) {
293 			case VParseHashElem::ELEM_INT:
294 			    sv = newSViv(elemp[j].val_int);
295 			    break;
296 			case VParseHashElem::ELEM_STR:
297 			default:
298 			    sv = newSVpv(elemp[j].val_str.c_str(), 0);
299 			    break;
300 			}
301 			hv_store(hv, elemp[j].keyp, strlen(elemp[j].keyp), sv, 0);
302 		    }
303 		    av_store(av, i, newRV_noinc((SV*)hv));
304 		    elemp++;
305 		}
306 		XPUSHs(sv_2mortal(newRV_noinc((SV*)av)));
307 	    } else if (textp) {  // Non hasharray_param, so is text
308 		XPUSHs(sv_2mortal(newSVpv(textp, 0)));
309 	    } else {
310 		XPUSHs(&PL_sv_undef);
311 	    }
312 	}
313 
314 	PUTBACK;			/* make local stack pointer global */
315 
316 	if (rtnStrp) {
317 	    int rtnCount = perl_call_method((char*)method, G_SCALAR);
318 	    SPAGAIN;			/* refresh stack pointer */
319 	    if (rtnCount > 0) {
320 		SV* sv = POPs;
321 		//printf("RTN %ld %d %s\n", SvTYPE(sv),SvTRUE(sv),SvPV_nolen(sv));
322 #ifdef SvPV_nolen	// Perl 5.6 and later
323 		*rtnStrp = SvPV_nolen(sv);
324 #else
325 		*rtnStrp = SvPV(sv,PL_na);
326 #endif
327 	    }
328 	    PUTBACK;
329 	} else {
330 	    perl_call_method((char*)method, G_DISCARD | G_VOID);
331 	}
332 
333 	FREETMPS;			/* free that return value */
334 	LEAVE;				/* ...and the XPUSHed "mortal" args.*/
335     }
336     va_end(ap);
337 }
338 
339 #//**********************************************************************
340 
341 MODULE = Verilog::Parser  PACKAGE = Verilog::Parser
342 
343 #//**********************************************************************
344 #// self->_new (class, sigparser)
345 
346 static VParserXs *
_new(SV * SELF,AV * symsp,bool sigparser,bool useUnreadback,bool useProtected,bool usePinselects)347 VParserXs::_new(SV* SELF, AV* symsp, bool sigparser, bool useUnreadback, bool useProtected, bool usePinselects)
348 PROTOTYPE: $$$$
349 CODE:
350 {
351     if (CLASS) {}  /* Prevent unused warning */
352     if (!SvROK(SELF)) { warn("${Package}::$func_name() -- SELF is not a hash reference"); }
353     VFileLineParseXs* filelinep = new VFileLineParseXs(NULL/*ok,for initial*/);
354     VParserXs* parserp = new VParserXs(filelinep, symsp, sigparser, useUnreadback, useProtected, usePinselects);
355     filelinep->setParser(parserp);
356     parserp->m_self = SvRV(SELF);
357     RETVAL = parserp;
358 }
359 OUTPUT: RETVAL
360 
361 #//**********************************************************************
362 #// self->_DESTROY()
363 
364 void
_DESTROY()365 VParserXs::_DESTROY()
366 PROTOTYPE: $
367 CODE:
368 {
369     delete THIS;
370 }
371 
372 #//**********************************************************************
373 #// self->debug(level)
374 
375 void
_debug(level)376 VParserXs::_debug(level)
377 int level
378 PROTOTYPE: $$
379 CODE:
380 {
381     THIS->debug(level);
382     VAstEnt::debug(level);
383 }
384 
385 #//**********************************************************************
386 #// self->_callback_master_enable(flag)
387 #// Turn off callbacks during std:: parsing
388 
389 void
_callback_master_enable(flag)390 VParserXs::_callback_master_enable(flag)
391 bool flag
392 PROTOTYPE: $$
393 CODE:
394 {
395     THIS->callbackMasterEna(flag);
396 }
397 
398 #//**********************************************************************
399 #// self->_use_cb(name,flag)
400 #// Turn off specified callback
401 
402 void
_use_cb(const char * name,bool flag)403 VParserXs::_use_cb(const char* name, bool flag)
404 PROTOTYPE: $$$
405 CODE:
406 {
407     THIS->useCbEna(name,flag);
408 }
409 
410 #//**********************************************************************
411 #// self->eof()
412 
413 void
eof()414 VParserXs::eof()
415 PROTOTYPE: $
416 CODE:
417 {
418     THIS->setEof();
419 }
420 #//**********************************************************************
421 #// self->filename([setit])
422 
423 SV*
424 VParserXs::filename(const char* flagp="")
425 PROTOTYPE: $;$
426 CODE:
427 {
428     if (!THIS) XSRETURN_UNDEF;
429     if (items > 1) {
430 	THIS->inFileline(flagp, THIS->inFilelinep()->lineno());
431 	THIS->cbFileline(THIS->inFilelinep());
432     }
433     string ret = THIS->cbFilelinep()->filename();
434     RETVAL = newSVpv(ret.c_str(), ret.length());
435 }
436 OUTPUT: RETVAL
437 
438 #//**********************************************************************
439 #// self->language()
440 
441 void
language(valuep)442 VParserXs::language(valuep)
443 const char* valuep
444 PROTOTYPE: $$
445 CODE:
446 {
447     if (items > 1) {
448         THIS->language(valuep);
449     }
450 }
451 
452 #//**********************************************************************
453 #// self->lineno([setit])
454 
455 int
456 VParserXs::lineno(int flag=0)
457 PROTOTYPE: $;$
458 CODE:
459 {
460     if (!THIS) XSRETURN_UNDEF;
461     if (items > 1) {
462 	THIS->inFileline(THIS->inFilelinep()->filename(), flag);
463 	THIS->cbFileline(THIS->inFilelinep());
464     }
465     RETVAL = (THIS->cbFilelinep()->lineno());
466 }
467 OUTPUT: RETVAL
468 
469 #//**********************************************************************
470 #// self->parse()
471 
472 void
parse(const char * textp)473 VParserXs::parse(const char* textp)
474 PROTOTYPE: $$
475 CODE:
476 {
477     THIS->parse(textp);
478 }
479 
480 #//**********************************************************************
481 #// self->selftest()
482 
483 void
selftest()484 VParserXs::selftest()
485 PROTOTYPE: $
486 CODE:
487 {
488     VSymStack::selftest();
489     assert(VParse::isKeyword("wire",strlen("wire")));
490     assert(!VParse::isKeyword("wire99",strlen("wide99")));
491 }
492 
493 #//**********************************************************************
494 #// self->unreadback()
495 
496 SV*
497 VParserXs::unreadback(const char* flagp="")
498 PROTOTYPE: $;$
499 CODE:
500 {
501     if (!THIS) XSRETURN_UNDEF;
502     // Set RETVAL to a SV before we replace with the new value, and c_str may change
503     string ret = THIS->unreadback();
504     RETVAL = newSVpv(ret.c_str(), ret.length());
505     if (items > 1) {
506 	THIS->unreadback(flagp);
507     }
508 }
509 OUTPUT: RETVAL
510 
511 #//**********************************************************************
512 #// self->unreadbackCat()
513 
514 void
unreadbackCat(SV * textsvp)515 VParserXs::unreadbackCat(SV* textsvp)
516 PROTOTYPE: $$
517 CODE:
518 {
519     if (!THIS) XSRETURN_UNDEF;
520     STRLEN textlen;
521     const char* textp = SvPV(textsvp, textlen);
522     THIS->unreadbackCat(textp, textlen);
523 }
524