1 #/* Verilog.xs -- Verilog Booter  -*- C++ -*-
2 #*********************************************************************
3 #*
4 #* DESCRIPTION: Verilog::Preproc 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 "VPreProc.h"
31 #include <deque>
32 
33 /* Perl */
34 extern "C" {
35 # include "EXTERN.h"
36 # include "perl.h"
37 # include "XSUB.h"
38 }
39 
40 #ifdef open
41 # undef open	/* Perl 64 bit on solaris has a nasty hack that redefines open */
42 #endif
43 
44 class VFileLineXs;
45 
46 #//**********************************************************************
47 #// Preprocessor derived classes, so we can override the callbacks to call perl.
48 
49 class VPreProcXs : public VPreProc {
50 public:
51     SV*		m_self;	// Class called from (the hash, not SV pointing to the hash)
52     deque<VFileLineXs*> m_filelineps;
53 
VPreProcXs()54     VPreProcXs() : VPreProc() {}
55     virtual ~VPreProcXs();
56 
57     // Callback methods
58     virtual void comment(string filename);	// Comment for keepComments=>sub
59     virtual void include(string filename);	// Request a include file be processed
60     virtual void define(string name, string value, string params); // `define with parameters
61     virtual void undef(string name);		// Remove a definition
62     virtual void undefineall();			// Remove all non-command-line definitions
63     virtual bool defExists(string name);	// Return true if define exists
64     virtual string defParams(string name);	// Return parameter list if define exists
65     virtual string defValue(string name);	// Return value of given define (should exist)
66     virtual string defSubstitute(string substitute);	// Return value to substitute for given post-parameter value
67 
68     void call(string* rtnStrp, int params, const char* method, ...);
69     void unreadback(char* text);
70 };
71 
72 class VFileLineXs : public VFileLine {
73     VPreProcXs*	m_vPreprocp;		// Parser handling the errors
74 public:
VFileLineXs(VPreProcXs * pp)75     VFileLineXs(VPreProcXs* pp) : VFileLine(true), m_vPreprocp(pp) { if (pp) pushFl(); }
~VFileLineXs()76     virtual ~VFileLineXs() { }
create(const string & filename,int lineno)77     virtual VFileLine* create(const string& filename, int lineno) {
78 	VFileLineXs* filelp = new VFileLineXs(m_vPreprocp);
79 	filelp->init(filename, lineno);
80 	return filelp;
81     }
82     virtual void error(const string& msg);	// Report a error at given location
setPreproc(VPreProcXs * pp)83     void setPreproc(VPreProcXs* pp) {
84 	m_vPreprocp=pp;
85 	pushFl(); // The very first construction used pp=NULL, as pp wasn't created yet so make it now
86     }
87     // Record the structure so we can delete it later
pushFl()88     void pushFl() { m_vPreprocp->m_filelineps.push_back(this); }
89 };
90 
91 #//**********************************************************************
92 #// Overrides error handling virtual functions to invoke callbacks
93 
error(const string & msg)94 void VFileLineXs::error(const string& msg) {
95     static string holdmsg; holdmsg = msg;
96     m_vPreprocp->call(NULL, 1,"error",holdmsg.c_str());
97 }
98 
99 #//**********************************************************************
100 #// VPreProcXs functions
101 
~VPreProcXs()102 VPreProcXs::~VPreProcXs() {
103     for (deque<VFileLineXs*>::iterator it=m_filelineps.begin(); it!=m_filelineps.end(); ++it) {
104 	delete *it;
105     }
106 }
107 
108 #//**********************************************************************
109 #// Overrides of virtual functions to invoke callbacks
110 
comment(string cmt)111 void VPreProcXs::comment(string cmt) {
112     static string holdcmt; holdcmt = cmt;
113     call(NULL, 1,"comment",holdcmt.c_str());
114 }
include(string filename)115 void VPreProcXs::include(string filename) {
116     static string holdfilename; holdfilename = filename;
117     call(NULL, 1,"include",holdfilename.c_str());
118 }
undef(string define)119 void VPreProcXs::undef(string define) {
120     static string holddefine; holddefine = define;
121     call(NULL, 1,"undef", holddefine.c_str());
122 }
undefineall()123 void VPreProcXs::undefineall() {
124     call(NULL, 0,"undefineall");
125 }
define(string define,string value,string params)126 void VPreProcXs::define(string define, string value, string params) {
127     static string holddefine; holddefine = define;
128     static string holdvalue; holdvalue = value;
129     static string holdparams; holdparams = params;
130     // 4th argument is cmdline; always undef from here
131     call(NULL, 3,"define", holddefine.c_str(), holdvalue.c_str(), holdparams.c_str());
132 }
defExists(string define)133 bool VPreProcXs::defExists(string define) {
134     return defParams(define)!="";
135 }
defParams(string define)136 string VPreProcXs::defParams(string define) {
137     static string holddefine; holddefine = define;
138     string paramStr;
139     call(&paramStr, 1,"def_params", holddefine.c_str());
140     return paramStr;
141 }
defValue(string define)142 string VPreProcXs::defValue(string define) {
143     static string holddefine; holddefine = define;
144     string valueStr;
145     call(&valueStr, 1,"def_value", holddefine.c_str());
146     return valueStr;
147 }
defSubstitute(string subs)148 string VPreProcXs::defSubstitute(string subs) {
149     static string holdsubs; holdsubs = subs;
150     string outStr;
151     call(&outStr, 1, "def_substitute", holdsubs.c_str());
152     return outStr;
153 }
154 
call(string * rtnStrp,int params,const char * method,...)155 void VPreProcXs::call(
156     string* rtnStrp,	/* If non-null, load return value here */
157     int params,		/* Number of parameters.  Negative frees the parameters */
158     const char* method,	/* Name of method to call */
159     ...)		/* Arguments to pass to method's @_ */
160 {
161     // Call $perlself->method (passedparam1, parsedparam2)
162     va_list ap;
163     va_start(ap, method);
164     {
165 	dSP;				/* Initialize stack pointer */
166 	ENTER;				/* everything created after here */
167 	SAVETMPS;			/* ...is a temporary variable. */
168 	PUSHMARK(SP);			/* remember the stack pointer */
169 	SV* selfsv = newRV_inc(m_self);	/* $self-> */
170 	XPUSHs(sv_2mortal(selfsv));
171 
172 	while (params--) {
173 	    char* text = va_arg(ap, char *);
174 	    SV* sv;
175 	    if (text) {
176 		sv = sv_2mortal(newSVpv(text, 0));
177 	    } else {
178 		sv = &PL_sv_undef;
179 	    }
180 	    XPUSHs(sv);			/* token */
181 	}
182 
183 	PUTBACK;			/* make local stack pointer global */
184 
185 	if (rtnStrp) {
186 	    int rtnCount = perl_call_method((char*)method, G_SCALAR);
187 	    SPAGAIN;			/* refresh stack pointer */
188 	    if (rtnCount > 0) {
189 		SV* sv = POPs;
190 		//printf("RTN %ld %d %s\n", SvTYPE(sv),SvTRUE(sv),SvPV_nolen(sv));
191 #ifdef SvPV_nolen	// Perl 5.6 and later
192 		*rtnStrp = SvPV_nolen(sv);
193 #else
194 		*rtnStrp = SvPV(sv,PL_na);
195 #endif
196 	    }
197 	    PUTBACK;
198 	} else {
199 	    perl_call_method((char*)method, G_DISCARD | G_VOID);
200 	}
201 
202 	FREETMPS;			/* free that return value */
203 	LEAVE;				/* ...and the XPUSHed "mortal" args.*/
204     }
205     va_end(ap);
206 }
207 
208 #//**********************************************************************
209 
210 MODULE = Verilog::Preproc  PACKAGE = Verilog::Preproc
211 
212 #//**********************************************************************
213 #// self->_new(class, keepcmt, keepwhite, linedir, pedantic, synthesis)
214 
215 static VPreProcXs *
_new(SELF,keepcmt,keepwhite,linedir,pedantic,synthesis)216 VPreProcXs::_new(SELF, keepcmt, keepwhite, linedir, pedantic, synthesis)
217 SV *SELF
218 int keepcmt
219 int keepwhite
220 int linedir
221 int pedantic
222 int synthesis
223 PROTOTYPE: $$$$$$
224 CODE:
225 {
226     if (CLASS) {}  /* Prevent unused warning */
227     if (!SvROK(SELF)) { warn("${Package}::$func_name() -- SELF is not a hash reference"); }
228     VFileLineXs* filelinep = new VFileLineXs(NULL/*ok,for initial*/);
229     VPreProcXs* preprocp = new VPreProcXs();
230     filelinep->setPreproc(preprocp);
231     preprocp->m_self = SvRV(SELF);
232     preprocp->keepComments(keepcmt);
233     preprocp->keepWhitespace(keepwhite);
234     preprocp->lineDirectives(linedir);
235     preprocp->pedantic(pedantic);
236     preprocp->synthesis(synthesis);
237     preprocp->configure(filelinep);
238     RETVAL = preprocp;
239 }
240 OUTPUT: RETVAL
241 
242 #//**********************************************************************
243 #// self->_DESTROY()
244 
245 void
_DESTROY()246 VPreProcXs::_DESTROY()
247 PROTOTYPE: $
248 CODE:
249 {
250     delete THIS;
251 }
252 #//**********************************************************************
253 #// self->debug()
254 
255 void
_debug(level)256 VPreProcXs::_debug(level)
257 int level
258 PROTOTYPE: $$
259 CODE:
260 {
261     THIS->debug(level);
262 }
263 
264 #//**********************************************************************
265 #// self->lineno()
266 
267 int
lineno()268 VPreProcXs::lineno()
269 PROTOTYPE: $
270 CODE:
271 {
272     if (!THIS) XSRETURN_UNDEF;
273     RETVAL = (THIS->fileline()->lineno());
274 }
275 OUTPUT: RETVAL
276 
277 #//**********************************************************************
278 #// self->filename()
279 
280 SV*
filename()281 VPreProcXs::filename()
282 PROTOTYPE: $
283 CODE:
284 {
285     if (!THIS) XSRETURN_UNDEF;
286     string ret = THIS->fileline()->filename();
287     RETVAL = newSVpv(ret.c_str(), ret.length());
288 }
289 OUTPUT: RETVAL
290 
291 #//**********************************************************************
292 #// self->unreadback()
293 
294 void
unreadback(text)295 VPreProcXs::unreadback(text)
296 char* text
297 PROTOTYPE: $$
298 CODE:
299 {
300     if (!THIS) XSRETURN_UNDEF;
301     THIS->insertUnreadback((string)text);
302 }
303 
304 #//**********************************************************************
305 #// self->getall()
306 
307 SV*
308 VPreProcXs::getall(approx_chunk=0)
309 size_t approx_chunk
310 PROTOTYPE: $;$
311 CODE:
312 {
313     static string holdline;
314     if (!THIS || THIS->isEof()) XSRETURN_UNDEF;
315     string lastline = THIS->getall(approx_chunk);
316     holdline = lastline;	/* Stash it so c_str() doesn't disappear immediately */
317     if (holdline=="" && THIS->isEof()) XSRETURN_UNDEF;
318     RETVAL = newSVpv(lastline.c_str(), lastline.length());
319 }
320 OUTPUT: RETVAL
321 
322 #//**********************************************************************
323 #// self->getline()
324 
325 SV*
getline()326 VPreProcXs::getline()
327 PROTOTYPE: $
328 CODE:
329 {
330     static string holdline;
331     if (!THIS || THIS->isEof()) XSRETURN_UNDEF;
332     string lastline = THIS->getline();
333     holdline = lastline;	/* Stash it so c_str() doesn't disappear immediately */
334     if (holdline=="" && THIS->isEof()) XSRETURN_UNDEF;
335     RETVAL = newSVpv(lastline.c_str(), lastline.length());
336 }
337 OUTPUT: RETVAL
338 
339 #//**********************************************************************
340 #// self->eof()
341 
342 int
eof()343 VPreProcXs::eof()
344 PROTOTYPE: $
345 CODE:
346 {
347     RETVAL = THIS->isEof();
348 }
349 OUTPUT: RETVAL
350 
351 #//**********************************************************************
352 #// self->_open(filename)
353 
354 int
_open(filename)355 VPreProcXs::_open(filename)
356 const char *filename
357 PROTOTYPE: $$
358 CODE:
359 {
360     if (!THIS) XSRETURN_UNDEF;
361     THIS->openFile(filename);
362     RETVAL = 1;
363 }
364 OUTPUT: RETVAL
365 
366