Minor bugfixes + parser is now based on tokens. Should ease reading other netlist formats significantly.

This commit is contained in:
Couriersud 2014-01-23 01:55:21 +00:00
parent 4737fe54cd
commit e7ed74b009
5 changed files with 494 additions and 244 deletions

View File

@ -266,7 +266,6 @@ void netlist_factory_t::initialize()
ENTRY(switch2, SWITCH2, "+i1,i2")
ENTRY(nicRSFF, NETDEV_RSFF, "+S,R")
ENTRY(7400, TTL_7400_NAND, "+A,B")
ENTRY(7400_dip, TTL_7400_DIP, "-")
ENTRY(7402, TTL_7402_NOR, "+A,B")
ENTRY(7404, TTL_7404_INVERT, "+A")
ENTRY(7410, TTL_7410_NAND, "+A,B,C")
@ -278,18 +277,19 @@ void netlist_factory_t::initialize()
ENTRY(7486, TTL_7486_XOR, "+A,B")
ENTRY(nic7448, TTL_7448, "+A0,A1,A2,A3,LTQ,BIQ,RBIQ")
ENTRY(7474, TTL_7474, "+CLK,D,CLRQ,PREQ")
ENTRY(7474_dip, TTL_7474_DIP, "-")
ENTRY(7483, TTL_7483, "+A1,A2,A3,A4,B1,B2,B3,B4,C0")
ENTRY(7490, TTL_7490, "+CLK,R1,R2,R91,R92")
ENTRY(7493, TTL_7493, "+CLKA,CLKB,R1,R2")
ENTRY(7493_dip, TTL_7493_DIP, "-")
ENTRY(74107, TTL_74107, "+CLK,J,K,CLRQ")
ENTRY(74107_dip, TTL_74107_DIP, "-")
ENTRY(74107A, TTL_74107A, "+CLK,J,K,CLRQ")
ENTRY(74153, TTL_74153, "+C0,C1,C2,C3,A,B,G")
ENTRY(9316, TTL_9316, "+CLK,ENP,ENT,CLRQ,LOADQ,A,B,C,D")
ENTRY(9316_dip, TTL_9316_DIP, "-")
ENTRY(NE555, NE555, "-")
ENTRY(7400_dip, TTL_7400_DIP, "-")
ENTRY(7474_dip, TTL_7474_DIP, "-")
ENTRY(7493_dip, TTL_7493_DIP, "-")
ENTRY(74107_dip, TTL_74107_DIP, "-")
ENTRY(9316_dip, TTL_9316_DIP, "-")
}
netlist_device_t *netlist_factory_t::new_device_by_classname(const pstring &classname, netlist_setup_t &setup) const

View File

@ -102,6 +102,16 @@ public:
return false;
}
ATTR_HOT inline int indexof(const _ListClass &elem) const
{
for (int i = 0; i < m_count; i++)
{
if (m_list[i] == elem)
return i;
}
return -1;
}
ATTR_HOT inline const _ListClass *first() const { return ((m_count > 0) ? &m_list[0] : NULL ); }
ATTR_HOT inline const _ListClass *next(const _ListClass *lc) const { return ((lc < last()) ? lc + 1 : NULL ); }
ATTR_HOT inline const _ListClass *last() const { return &m_list[m_count -1]; }

View File

@ -11,10 +11,232 @@
//#define NL_VERBOSE_OUT(x) printf x
// ----------------------------------------------------------------------------------------
// A netlist parser
// A simple tokenizer
// ----------------------------------------------------------------------------------------
ATTR_COLD void netlist_parser::error(const char *format, ...)
pstring ptokenizer::currentline_str()
{
char buf[300];
int bufp = 0;
const char *p = m_line_ptr;
while (*p && *p != 10)
buf[bufp++] = *p++;
buf[bufp] = 0;
return pstring(buf);
}
void ptokenizer::skipeol()
{
char c = getc();
while (c)
{
if (c == 10)
{
c = getc();
if (c != 13)
ungetc();
return;
}
c = getc();
}
}
void ptokenizer::skipws()
{
while (unsigned char c = getc())
{
switch (c)
{
case ' ':
case 9:
case 10:
case 13:
break;
case '#':
skipeol(); // treat preprocessor defines as comments
break;
case '/':
c = getc();
if (c == '/')
{
skipeol();
}
else if (c == '*')
{
int f=0;
while (!eof() )
{
c = getc();
if (f == 0 && c == '*')
f=1;
else if (f == 1 && c== '/' )
break;
else
f=0;
}
}
break;
default:
ungetc();
return;
}
}
}
unsigned char ptokenizer::peekc()
{
unsigned char c = getc();
ungetc();
return c;
}
unsigned char ptokenizer::getc()
{
if (*m_px == 10)
{
m_line++;
m_line_ptr = m_px + 1;
}
if (*m_px)
return *(m_px++);
else
return *m_px;
}
void ptokenizer::ungetc()
{
m_px--;
}
void ptokenizer::require_token(const token_id_t &token_num)
{
require_token(get_token(), token_num);
}
void ptokenizer::require_token(const token_t tok, const token_id_t &token_num)
{
if (!tok.is(token_num))
{
error("Error: expected token <%s> got <%s>\n", m_tokens[token_num.id()].cstr(), tok.str().cstr());
}
}
pstring ptokenizer::get_string()
{
token_t tok = get_token();
if (!tok.is_type(STRING))
{
error("Error: expected a string, got <%s>\n", tok.str().cstr());
}
return tok.str();
}
pstring ptokenizer::get_identifier()
{
token_t tok = get_token();
if (!tok.is_type(IDENTIFIER))
{
error("Error: expected an identifier, got <%s>\n", tok.str().cstr());
}
return tok.str();
}
ptokenizer::token_t ptokenizer::get_token()
{
while (true)
{
token_t ret = get_token_internal();
if (ret.is_type(ENDOFFILE))
return ret;
if (ret.is(m_tok_comment_start))
{
do {
ret = get_token_internal();
} while (ret.is_not(m_tok_comment_end));
}
else if (ret.is(m_tok_line_comment))
{
skipeol();
}
else if (ret.str() == "#")
{
skipeol();
}
else
return ret;
}
}
ptokenizer::token_t ptokenizer::get_token_internal()
{
/* skip ws */
char c = getc();
while (m_whitespace.find(c)>=0)
{
c = getc();
if (eof())
{
return token_t(ENDOFFILE);
}
}
if (m_identifier_chars.find(c)>=0)
{
/* read identifier till non identifier char */
pstring tokstr = "";
while (m_identifier_chars.find(c)>=0) {
tokstr += c;
c = getc();
}
ungetc();
token_id_t id = token_id_t(m_tokens.indexof(tokstr));
if (id.id() >= 0)
return token_t(id, tokstr);
else
{
return token_t(IDENTIFIER, tokstr);
}
}
else if (c == m_string)
{
pstring tokstr = "";
c = getc();
while (c != m_string)
{
tokstr += c;
c = getc();
}
return token_t(STRING, tokstr);
}
else
{
/* read identifier till first identifier char or ws */
pstring tokstr = "";
while ((m_identifier_chars.find(c)) < 0 && (m_whitespace.find(c) < 0)) {
tokstr += c;
/* expensive, check for single char tokens */
if (tokstr.len() == 1)
{
token_id_t id = token_id_t(m_tokens.indexof(tokstr));
if (id.id() >= 0)
return token_t(id, tokstr);
}
c = getc();
}
ungetc();
token_id_t id = token_id_t(m_tokens.indexof(tokstr));
if (id.id() >= 0)
return token_t(id, tokstr);
else
{
return token_t(UNKNOWN, tokstr);
}
}
}
ATTR_COLD void ptokenizer::error(const char *format, ...)
{
va_list ap;
va_start(ap, format);
@ -22,14 +244,19 @@ ATTR_COLD void netlist_parser::error(const char *format, ...)
pstring errmsg1 =pstring(format).vprintf(ap);
va_end(ap);
char buf[300];
int bufp = 0;
const char *p = m_line_ptr;
while (*p && *p != 10)
buf[bufp++] = *p++;
buf[bufp] = 0;
verror(errmsg1, currentline_no(), currentline_str());
m_setup.netlist().error("line %d: error: %s\n\t\t%s\n", m_line, errmsg1.cstr(), buf);
//throw error;
}
// ----------------------------------------------------------------------------------------
// A netlist parser
// ----------------------------------------------------------------------------------------
ATTR_COLD void netlist_parser::verror(pstring msg, int line_num, pstring line)
{
m_setup.netlist().error("line %d: error: %s\n\t\t%s\n", line_num,
msg.cstr(), line.cstr());
//throw error;
}
@ -37,77 +264,100 @@ ATTR_COLD void netlist_parser::error(const char *format, ...)
void netlist_parser::parse(const char *buf)
{
m_px = buf;
m_line_ptr = buf;
m_line = 1;
reset(buf);
set_identifier_chars("abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-");
set_number_chars("01234567890eE-."); //FIXME: processing of numbers
char ws[5];
ws[0] = ' ';
ws[1] = 9;
ws[2] = 10;
ws[3] = 13;
ws[4] = 0;
set_whitespace(ws);
set_comment("/*", "*/", "//");
m_tok_param_left = register_token("(");
m_tok_param_right = register_token(")");
m_tok_comma = register_token(",");
while (!eof())
m_tok_ALIAS = register_token("ALIAS");
m_tok_NET_C = register_token("NET_C");
m_tok_PARAM = register_token("PARAM");
m_tok_NET_MODEL = register_token("PARAM");
m_tok_NETLIST_START = register_token("NETLIST_START");
m_tok_NETLIST_END = register_token("NETLIST_END");
while (true)
{
pstring n;
skipws();
if (eof()) break;
n = getname('(');
NL_VERBOSE_OUT(("Parser: Device: %s\n", n.cstr()));
if (n == "ALIAS")
net_alias();
else if (n == "NET_C")
net_c();
else if (n == "PARAM")
netdev_param();
else if ((n == "NET_MODEL"))
net_model();
else if (n == "NETLIST_START")
netdev_netlist_start();
else if (n == "NETLIST_END")
token_t token = get_token();
if (token.is_type(ENDOFFILE))
return;
require_token(m_tok_param_left);
NL_VERBOSE_OUT(("Parser: Device: %s\n", n.cstr()));
if (token.is(m_tok_ALIAS))
net_alias();
else if (token.is(m_tok_NET_C))
net_c();
else if (token.is(m_tok_PARAM))
netdev_param();
else if (token.is(m_tok_NET_MODEL))
net_model();
else if (token.is(m_tok_NETLIST_START))
netdev_netlist_start();
else if (token.is(m_tok_NETLIST_END))
netdev_netlist_end();
else
device(n);
else
device(token.str());
}
}
void netlist_parser::netdev_netlist_start()
{
// don't do much
skipws();
/*pstring dummyname = */ getname(')');
//check_char(')');
token_t name = get_token();
require_token(m_tok_param_right);
}
void netlist_parser::netdev_netlist_end()
{
// don't do much
skipws();
check_char(')');
require_token(m_tok_param_right);
}
void netlist_parser::net_model()
{
// don't do much
pstring model = getstring();
pstring model = get_string();
m_setup.register_model(model);
check_char(')');
require_token(m_tok_param_right);
}
void netlist_parser::net_alias()
{
pstring alias;
pstring out;
skipws();
alias = getname(',');
skipws();
out = getname(')');
pstring alias = get_identifier();
require_token(m_tok_comma);
pstring out = get_identifier();
require_token(m_tok_param_right);
NL_VERBOSE_OUT(("Parser: Alias: %s %s\n", alias.cstr(), out.cstr()));
m_setup.register_alias(alias, out);
}
void netlist_parser::net_c()
{
pstring t1;
pstring t2;
skipws();
t1 = getname(',');
skipws();
t2 = getname(')');
pstring t1 = get_identifier();
require_token(m_tok_comma);
pstring t2 = get_identifier();
require_token(m_tok_param_right);
NL_VERBOSE_OUT(("Parser: Connect: %s %s\n", t1.cstr(), t2.cstr()));
m_setup.register_link(t1 , t2);
}
@ -116,13 +366,12 @@ void netlist_parser::netdev_param()
{
pstring param;
double val;
skipws();
param = getname(',');
skipws();
val = eval_param();
param = get_identifier();
require_token(m_tok_comma);
val = eval_param(get_token());
NL_VERBOSE_OUT(("Parser: Param: %s %f\n", param.cstr(), val));
m_setup.register_param(param, val);
check_char(')');
require_token(m_tok_param_right);
}
void netlist_parser::device(const pstring &dev_type)
@ -132,11 +381,12 @@ void netlist_parser::device(const pstring &dev_type)
netlist_device_t *dev;
nl_util::pstring_list termlist = f->term_param_list();
pstring def_param = f->def_param();
token_t tok;
int cnt;
skipws();
devname = getname2(',', ')');
devname = get_identifier();
dev = f->Create();
m_setup.register_dev(dev, devname);
@ -146,35 +396,34 @@ void netlist_parser::device(const pstring &dev_type)
{
pstring paramfq = devname + "." + def_param;
NL_VERBOSE_OUT(("Defparam: %s\n", def_param.cstr()));
check_char(',');
skipws();
if (peekc() == '"')
require_token(m_tok_comma);
tok = get_token();
if (tok.is_type(STRING))
{
pstring val = getstring();
m_setup.register_param(paramfq, val);
m_setup.register_param(paramfq, tok.str());
}
else
{
double val = eval_param();
double val = eval_param(tok);
m_setup.register_param(paramfq, val);
}
if (termlist.count() > 0)
check_char(',');
}
tok = get_token();
cnt = 0;
while (getc() != ')' && cnt < termlist.count())
while (tok.is(m_tok_comma) && cnt < termlist.count())
{
skipws();
pstring output_name = getname2(',', ')');
pstring output_name = get_identifier();
m_setup.register_link(devname + "." + termlist[cnt], output_name);
skipws();
cnt++;
tok = get_token();
}
if (cnt != termlist.count())
fatalerror("netlist: input count mismatch for %s - expected %d found %d\n", devname.cstr(), termlist.count(), cnt);
require_token(tok, m_tok_param_right);
}
@ -182,167 +431,35 @@ void netlist_parser::device(const pstring &dev_type)
// private
// ----------------------------------------------------------------------------------------
void netlist_parser::skipeol()
{
char c = getc();
while (c)
{
if (c == 10)
{
c = getc();
if (c != 13)
ungetc();
return;
}
c = getc();
}
}
void netlist_parser::skipws()
double netlist_parser::eval_param(const token_t tok)
{
while (unsigned char c = getc())
{
switch (c)
{
case ' ':
case 9:
case 10:
case 13:
break;
case '#':
skipeol(); // treat preprocessor defines as comments
break;
case '/':
c = getc();
if (c == '/')
{
skipeol();
}
else if (c == '*')
{
int f=0;
while (!eof() )
{
c = getc();
if (f == 0 && c == '*')
f=1;
else if (f == 1 && c== '/' )
break;
else
f=0;
}
}
break;
default:
ungetc();
return;
}
}
}
pstring netlist_parser::getstring()
{
skipws();
check_char('"');
pstring ret = getname2_ext('"', 0, NULL);
check_char('"');
skipws();
return ret;
}
pstring netlist_parser::getname(char sep)
{
pstring ret = getname2(sep, 0);
getc(); // undo the undo ...
return ret;
}
pstring netlist_parser::getname2(char sep1, char sep2)
{
static const char *allowed = "0123456789_.ABCDEFGHIJKLMNOPQRSTUVWXYZ";
return getname2_ext(sep1, sep2, allowed);
}
pstring netlist_parser::getname2_ext(char sep1, char sep2, const char *allowed)
{
char buf[1024];
char *p1 = buf;
char c=getc();
while ((c != sep1) && (c != sep2))
{
char cU = toupper(c);
if ((allowed == NULL) || strchr(allowed, cU) != NULL)
*p1++ = c;
else
{
*p1 = 0;
error("illegal character <%c> in name ...\n", c);
}
c = getc();
}
*p1 = 0;
ungetc();
return pstring(buf);
}
void netlist_parser::check_char(char ctocheck)
{
skipws();
char c = getc();
if ( c == ctocheck)
{
return;
}
error("expected '%c' found '%c'\n", ctocheck, c);
}
double netlist_parser::eval_param()
{
static const char *macs[6] = {"", "RES_K(", "RES_M(", "CAP_U(", "CAP_N(", "CAP_P("};
static const char *allowed = "RESKMUNPAC_0123456789E(+-.";
static const char *macs[6] = {"", "RES_K", "RES_M", "CAP_U", "CAP_N", "CAP_P"};
static double facs[6] = {1, 1e3, 1e6, 1e-6, 1e-9, 1e-12};
int i;
int f=0;
bool e;
double ret;
pstring val;
pstring s = getname2_ext(')',',', allowed);
//printf("param %s\n", tok.m_token.cstr());
for (i=1; i<6;i++)
if (strncmp(s.cstr(), macs[i], strlen(macs[i])) == 0)
if (tok.str().equals(macs[i]))
f = i;
if (f>0)
check_char(')');
s = s.substr(strlen(macs[f]));
ret = s.as_double(&e);
// if ((f>0) && e)
if (e)
{
require_token(m_tok_param_left);
val = get_identifier();
}
else
val = tok.str();
ret = val.as_double(&e);
if (e)
error("Error with parameter ...\n");
if (f>0)
require_token(m_tok_param_right);
return ret * facs[f];
}
unsigned char netlist_parser::peekc()
{
unsigned char c = getc();
ungetc();
return c;
}
unsigned char netlist_parser::getc()
{
if (*m_px == 10)
{
m_line++;
m_line_ptr = m_px + 1;
}
if (*m_px)
return *(m_px++);
else
return *m_px;
}
void netlist_parser::ungetc()
{
m_px--;
}

View File

@ -10,12 +10,139 @@
#include "nl_setup.h"
class netlist_parser
class ptokenizer
{
NETLIST_PREVENT_COPYING(ptokenizer)
public:
ptokenizer()
: m_line(1), m_line_ptr(NULL), m_px(NULL)
{}
enum token_type
{
IDENTIFIER,
NUMBER,
TOKEN,
STRING,
COMMENT,
UNKNOWN,
ENDOFFILE,
};
struct token_id_t
{
public:
token_id_t() : m_id(-2) {}
token_id_t(const int id) : m_id(id) {}
const int id() const { return m_id; }
private:
int m_id;
};
struct token_t
{
token_t() {};
token_t(token_type type)
{
m_type = type;
m_id = token_id_t(-1);
m_token ="";
}
token_t(token_type type, const pstring str)
{
m_type = type;
m_id = token_id_t(-1);
m_token = str;
}
token_t(const token_id_t id, const pstring str)
{
m_type = TOKEN;
m_id = id;
m_token = str;
}
bool is(const token_id_t &tok_id) const { return m_id.id() == tok_id.id(); }
bool is_not(const token_id_t &tok_id) const { return !is(tok_id); }
bool is_type(const token_type type) const { return m_type == type; }
pstring str() const { return m_token; }
private:
token_type m_type;
token_id_t m_id;
pstring m_token;
};
int currentline_no() { return m_line; }
pstring currentline_str();
/* tokenizer stuff follows ... */
token_t get_token();
pstring get_string();
pstring get_identifier();
void require_token(const token_id_t &token_num);
void require_token(const token_t tok, const token_id_t &token_num);
token_id_t register_token(pstring token)
{
m_tokens.add(token);
return token_id_t(m_tokens.count() - 1);
}
void set_identifier_chars(pstring s) { m_identifier_chars = s; }
void set_number_chars(pstring s) { m_number_chars = s; }
void set_whitespace(pstring s) { m_whitespace = s; }
void set_comment(pstring start, pstring end, pstring line)
{
m_tok_comment_start = register_token(start);
m_tok_comment_end = register_token(end);
m_tok_line_comment = register_token(line);
m_string = '"';
}
token_t get_token_internal();
void error(const char *format, ...);
protected:
void reset(const char *p) { m_px = p; m_line = 1; m_line_ptr = p; }
virtual void verror(pstring msg, int line_num, pstring line) = 0;
private:
void skipeol();
void skipws();
unsigned char peekc();
unsigned char getc();
void ungetc();
bool eof() { return *m_px == 0; }
int m_line;
const char * m_line_ptr;
const char * m_px;
/* tokenizer stuff follows ... */
pstring m_identifier_chars;
pstring m_number_chars;
netlist_list_t<pstring> m_tokens;
pstring m_whitespace;
char m_string;
token_id_t m_tok_comment_start;
token_id_t m_tok_comment_end;
token_id_t m_tok_line_comment;
};
class netlist_parser : public ptokenizer
{
NETLIST_PREVENT_COPYING(netlist_parser)
public:
netlist_parser(netlist_setup_t &setup)
: m_line(1), m_line_ptr(NULL), m_px(NULL), m_setup(setup) {}
: ptokenizer(), m_setup(setup) {}
void parse(const char *buf);
void net_alias();
@ -26,27 +153,23 @@ public:
void netdev_netlist_end();
void net_model();
void error(const char *format, ...);
protected:
virtual void verror(pstring msg, int line_num, pstring line);
private:
void skipeol();
void skipws();
pstring getname(char sep);
pstring getname2(char sep1, char sep2);
pstring getname2_ext(char sep1, char sep2, const char *allowed);
void check_char(char ctocheck);
double eval_param();
pstring getstring();
double eval_param(const token_t tok);
unsigned char peekc();
unsigned char getc();
void ungetc();
bool eof() { return *m_px == 0; }
token_id_t m_tok_param_left;
token_id_t m_tok_param_right;
token_id_t m_tok_comma;
token_id_t m_tok_ALIAS;
token_id_t m_tok_NET_C;
token_id_t m_tok_PARAM;
token_id_t m_tok_NET_MODEL;
token_id_t m_tok_NETLIST_START;
token_id_t m_tok_NETLIST_END;
int m_line;
const char * m_line_ptr;
const char * m_px;
netlist_setup_t &m_setup;
netlist_setup_t &m_setup;
};

View File

@ -120,8 +120,8 @@ public:
//
inline int len() const { return m_ptr->len(); }
inline bool equals(const pstring &string) { return (pcmp(string.cstr(), m_ptr->str()) == 0); }
inline bool iequals(const pstring &string) { return (pcmpi(string.cstr(), m_ptr->str()) == 0); }
inline bool equals(const pstring &string) const { return (pcmp(string.cstr(), m_ptr->str()) == 0); }
inline bool iequals(const pstring &string) const { return (pcmpi(string.cstr(), m_ptr->str()) == 0); }
inline int cmp(const pstring &string) const { return pcmp(string.cstr()); }
inline int cmpi(const pstring &string) const { return pcmpi(cstr(), string.cstr()); }