You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gnucap-custom/c_vpp.cc

331 lines
8.7 KiB
C++

/* -*- C++ -*-
* Copyright (C) 2018 Felix Salfelder
* Author: Felix Salfelder <felix@salfelder.org>
*
* This file is part of "Gnucap", the Gnu Circuit Analysis Package
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*------------------------------------------------------------------
* non-sophisticated verilog preprocessor stub
* `define, `ifdef, `ifndef, constants only. enough for include guards.
*/
#include <c_comand.h>
#include <ap.h>
#include <globals.h>
#include <u_lang.h>
#include <stack>
#include <e_subckt.h>
#include <d_coment.h>
extern std::stack<CARD*> owner_hack;
namespace {
/*--------------------------------------------------------------------------*/
class CMD_VPP_DEFINE : public CMD {
public:
CMD_VPP_DEFINE() {
_defs["GNUCAP"];
}
public:
void do_it(CS& cmd, CARD_LIST* Scope) {
if(Scope){ untested();
}else{ untested();
}
std::string what;
cmd >> what;
trace2("def", cmd.fullstring(), what);
if(defined(what)){
error(bPICKY, "already defined: %s\n", what.c_str());
}else{
_defs[what];
}
}
bool defined(std::string const& what) const{
bool v=_defs.find(what)!=_defs.end();
trace2("defined", what, v);
return v;
}
void undef(std::string const& what){
auto v=_defs.find(what);
if(v!=_defs.end()){
_defs.erase(v);
}else{
error(bPICKY, "not defined: %s\n", what.c_str());
}
}
private:
std::map<std::string, std::string> _defs;
} p_define;
DISPATCHER<CMD>::INSTALL d_define(&command_dispatcher, "`define", &p_define);
/*--------------------------------------------------------------------------*/
class CMD_VPP_IF : public CMD {
public:
enum status_t {
c_disabled=0,
c_active=1,
c_past_else=2,
c_done=4
};
public:
CMD_VPP_IF() : CMD(){
}
~CMD_VPP_IF() {
assert(!_nest.size());
}
public:
void do_it(CS& cmd, CARD_LIST* Scope) {
trace1("if", Scope);
if(cmd.umatch("0 ")){
if0(cmd, Scope);
}else if(cmd.umatch("1 ")){
if1(cmd, Scope);
}else{ untested();
incomplete();
}
}
public:
void if0(CS& cmd, CARD_LIST* Scope){
status_t t = c_disabled;
if(!_nest.size()){
}else if(c_active & _nest.top()){
}else{
t = status_t(t | c_done);
}
_nest.push(t);
cond_block(cmd, Scope, true);
}
void if1(CS& cmd, CARD_LIST* Scope){
status_t t = c_active;
if(_nest.size()){
t = status_t(c_active & _nest.top());
}else{
}
_nest.push(t);
set(c_done);
cond_block(cmd, Scope, true);
}
private:
// allow_else: we haven't seen an "else" yet.
void cond_block(CS& cmd, CARD_LIST* scope, bool allow_else){
BASE_SUBCKT* o=NULL;
if(scope!=&CARD_LIST::card_list){
assert(!owner_hack.empty());
trace1("not toplevel, need owner", scope->parent());
o = prechecked_cast<BASE_SUBCKT*>(owner_hack.top());
assert(o);
// o->scope()->params()->set_try_again(scope->params());
}else{
trace0("no owner");
}
assert(_nest.size());
size_t depth = _nest.size()-1;
trace3("cond push ", cmd.fullstring(), allow_else, _nest.size());
for (;;) {
assert(OPT::language);
cmd.get_line("gnucap->");
trace3("got...", cmd.fullstring(), _nest.size(), depth);
if(_nest.top() & c_active){
OPT::language->new__instance(cmd, o, scope);
}else if(cmd.umatch("`elsif ")){
cmd.reset();
OPT::language->new__instance(cmd, o, scope);
}else if(cmd.umatch("`ifdef|`ifndef ")){
cmd.reset();
OPT::language->new__instance(cmd, o, scope);
}else if(cmd.umatch("`if ")){
cmd.reset();
OPT::language->new__instance(cmd, o, scope);
}else if(cmd.umatch("`else ")){
cmd.reset();
OPT::language->new__instance(cmd, o, scope);
}else if(cmd.umatch("`endif ")){
cmd.reset();
OPT::language->new__instance(cmd, o, scope);
}else{
trace3("ignoring nested...", cmd.fullstring(), o, cmd.peek());
CARD* x=device_dispatcher.clone("dev_comment");
DEV_COMMENT* c=prechecked_cast<DEV_COMMENT*>(x);
assert(c);
OPT::language->parse_comment(cmd, c);
scope->push_back(x);
}
trace3("parsed...", cmd.fullstring(), _nest.size(), depth);
if(_nest.size()==depth){
// past endif
break;
}else{
}
}
}
public:
bool is(status_t x){
assert(_nest.size());
return _nest.top() & x;
}
void set(status_t x){
assert(_nest.size());
_nest.top() = status_t( _nest.top() | x );
}
void unset(status_t x){
assert(_nest.size());
_nest.top() = status_t( _nest.top() & ~x );
}
private:
std::map<std::string, std::string> _defs;
public:
std::stack<status_t> _nest;
} p_if;
DISPATCHER<CMD>::INSTALL d0(&command_dispatcher, "`if", &p_if);
/*--------------------------------------------------------------------------*/
class CMD_VPP_ELSE : public CMD {
public:
CMD_VPP_ELSE() : CMD(){
}
public:
void do_it(CS& cmd, CARD_LIST* Scope) {
if(Scope){ untested();
}else{ untested();
}
trace1("`else", p_if._nest.size());
if(!p_if._nest.size()){
cmd.warn(bDANGER, 0, "misplaced else");
}else if(p_if.is(CMD_VPP_IF::c_past_else)){
cmd.warn(bDANGER, 0, "double else");
}else if(p_if.is(CMD_VPP_IF::c_done)){
p_if.set( CMD_VPP_IF::c_past_else );
p_if.unset( CMD_VPP_IF::c_active );
}else if(p_if.is(CMD_VPP_IF::c_active)){ untested();
unreachable(); // implies "done".
}else{
trace1("top is else branch", p_if._nest.size());
// no further else please.
// p_if._nest.pop();
p_if.set(CMD_VPP_IF::c_past_else );
p_if.set(CMD_VPP_IF::c_done );
p_if.set(CMD_VPP_IF::c_active);
}
}
} p_else;
DISPATCHER<CMD>::INSTALL d_else(&command_dispatcher, "`else", &p_else);
/*--------------------------------------------------------------------------*/
class CMD_VPP_ENDIF : public CMD {
public:
void do_it(CS& cmd, CARD_LIST* Scope) {
if(Scope){ untested();
}else{ untested();
}
trace2("endif", cmd.fullstring(), p_if._nest.size());
if(!p_if._nest.size()){
cmd.warn(bDANGER, 0, "unmatched endif");
}else if(p_if._nest.top() & p_if.c_active){
p_if._nest.pop();
}else{
p_if._nest.pop();
}
}
} p_endif;
DISPATCHER<CMD>::INSTALL d_endif(&command_dispatcher, "`endif", &p_endif);
/*--------------------------------------------------------------------------*/
class CMD_VPP_UNDEF : public CMD {
public:
void do_it(CS& cmd, CARD_LIST* Scope) {
if(Scope){ untested();
}else{ untested();
}
std::string what;
cmd >> what;
p_define.undef(what);
}
} p_undef;
DISPATCHER<CMD>::INSTALL d_undef(&command_dispatcher, "`undef", &p_undef);
/*--------------------------------------------------------------------------*/
class CMD_VPP_IFDEF : public CMD {
public:
CMD_VPP_IFDEF() : CMD(){
}
public:
void do_it(CS& cmd, CARD_LIST* Scope)
{
std::string what;
cmd >> what;
if (p_define.defined(what)){
p_if.if1(cmd, Scope);
}else{
p_if.if0(cmd, Scope);
}
}
} p_ifdef;
DISPATCHER<CMD>::INSTALL d_ifdef(&command_dispatcher, "`ifdef", &p_ifdef);
/*--------------------------------------------------------------------------*/
class CMD_VPP_ELSIF : public CMD {
public:
CMD_VPP_ELSIF() : CMD(){
}
public:
void do_it(CS& cmd, CARD_LIST* Scope) {
if(Scope){ untested();
}else{ untested();
}
if (!p_if._nest.size()){
cmd.warn(bDANGER, 0, "misplaced `elsif");
}else if( p_if.is(CMD_VPP_IF::c_past_else ) ){
cmd.warn(bDANGER, 0, "`elsif after else?");
p_if.unset(CMD_VPP_IF::c_active);
}else if(p_if.is(CMD_VPP_IF::c_done)){
// no need to evaluate, TODO: parse
p_if.unset(CMD_VPP_IF::c_active);
}else if(!(p_if.is(CMD_VPP_IF::c_active))){
std::string w;
cmd >> w;
if(p_define.defined(w)){
p_if.set(CMD_VPP_IF::c_active);
p_if.set(CMD_VPP_IF::c_done);
}else{
}
}else{ untested();
unreachable();
// active implies done
}
}
} p_elif;
DISPATCHER<CMD>::INSTALL d3(&command_dispatcher, "`elsif", &p_elif);
/*--------------------------------------------------------------------------*/
class CMD_VPP_IFNDEF : public CMD {
public:
void do_it(CS& cmd, CARD_LIST* Scope)
{
std::string what;
cmd >> what;
if (p_define.defined(what)){
p_if.if0(cmd, Scope);
}else{
p_if.if1(cmd, Scope);
}
}
} p_ifndef;
DISPATCHER<CMD>::INSTALL d_ifndef(&command_dispatcher, "`ifndef", &p_ifndef);
/*--------------------------------------------------------------------------*/
}
// vim:noet