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