view ueda/libuschem/rdschem_parse.c @ 139:bf188727e606

donl-rename-parts reader: no tEDAx-style escapes
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 07 Sep 2020 04:25:11 +0000
parents cd92449fdb51
children
line wrap: on
line source

/*
 * uschem schematic parser
 */

#include <sys/types.h>
#include <stdio.h>
#include <strings.h>
#include "schemstruct.h"
#include "parserint.h"

extern char *copystr();

extern struct schem_parse_state schem_parse_state;

extern struct schemobj *parser_alloc_obj();
extern struct decoration *parser_alloc_decor();
extern struct netpoint *parser_alloc_netpoint();
extern struct xypair parse_drawing_size_spec();
extern struct graphblock *rdschem_graphblock();

rdschem_parse_schemline()
{
	register int t;
	struct xypair drawing_size;

	t = rdschem_token();
	if (t != STRING || strcmp(schem_parse_state.string, "Schem")) {
		fprintf(stderr,
		"%s is not a uschem schematic (doesn't begin with Schem)\n",
			schem_parse_state.schem->orig_filename);
		exit(1);
	}

	t = rdschem_token();
	if (t != STRING)
inv:		rdschem_error("Schem line: syntax error");
	if (!strcmp(schem_parse_state.string, "graph")) {
		schem_parse_state.schem->is_graph = 1;
		t = rdschem_token();
		if (t != STRING && t != QSTRING)
			goto inv;
		drawing_size =
			parse_drawing_size_spec(schem_parse_state.string);
		schem_parse_state.schem->graph_xsize = drawing_size.x;
		schem_parse_state.schem->graph_ysize = drawing_size.y;
	} else if (!strcmp(schem_parse_state.string, "nograph"))
		schem_parse_state.schem->is_graph = 0;
	else
		goto inv;

	t = rdschem_token();
	if (t != ';')
		goto inv;
}

static struct decoration *
parse_decor_attr()
{
	register struct decoration *decor;
	register int t;

	decor = parser_alloc_decor(DECOR_TYPE_ATTR);
	t = rdschem_token();
	if (t != STRING && t != QSTRING)
syntaxerr:	rdschem_error("(attribute definition decoration) syntax error");
	if (!schem_parse_state.string[0])
		rdschem_error("attribute name may not be a null string");
	decor->decorattr_name = copystr(schem_parse_state.string);
	t = rdschem_token();
	if (t != '=')
		goto syntaxerr;
	t = rdschem_token();
	if (t != STRING && t != QSTRING)
		goto syntaxerr;
	if (!schem_parse_state.string[0])
		rdschem_error("attribute value may not be a null string");
	decor->decorattr_value = copystr(schem_parse_state.string);
	t = rdschem_token();
	if (t != ')')
		goto syntaxerr;
	return(decor);
}

static struct decoration *
parse_decor_displayattr()
{
	register struct decoration *decor;
	register int t;

	decor = parser_alloc_decor(DECOR_TYPE_DISPLAYATTR);
	t = rdschem_token();
	if (t != STRING && t != QSTRING)
syntaxerr:	rdschem_error("(DisplayAttr decoration) syntax error");
	if (!schem_parse_state.string[0])
		rdschem_error("attribute name may not be a null string");
	decor->decordisp_attr = copystr(schem_parse_state.string);
	decor->decordisp_x = parse_number();
	decor->decordisp_y = parse_number();
	decor->decordisp_ptsize = parse_number();
	decor->decordisp_rotate = parse_number();
	decor->decordisp_alignment = parse_number();
	t = rdschem_token();
	if (t != ';')
		goto syntaxerr;
	return(decor);
}

static struct decoration *
parse_decor_displaynetname()
{
	register struct decoration *decor;
	register int t;

	decor = parser_alloc_decor(DECOR_TYPE_DISPLAYNETNAME);
	decor->decordisp_x = parse_number();
	decor->decordisp_y = parse_number();
	decor->decordisp_ptsize = parse_number();
	decor->decordisp_rotate = parse_number();
	decor->decordisp_alignment = parse_number();
	t = rdschem_token();
	if (t != ';')
		rdschem_error("(DisplayNetName decoration) syntax error");
	return(decor);
}

static struct decoration *
parse_decor_pintonet()
{
	register struct decoration *decor;
	register int t;

	decor = parser_alloc_decor(DECOR_TYPE_PINTONET);
	t = rdschem_token();
	if (t != STRING && t != QSTRING)
syntaxerr:	rdschem_error("(PinToNet decoration) syntax error");
	if (!schem_parse_state.string[0])
		rdschem_error("pin ID may not be a null string");
	if (!strcmp(schem_parse_state.string, "#"))
		rdschem_error("pin ID \"#\" is invalid");
	decor->decorpincon_pin = copystr(schem_parse_state.string);
	t = rdschem_token();
	if (t != STRING && t != QSTRING)
		goto syntaxerr;
	if (!schem_parse_state.string[0])
		rdschem_error("net name may not be a null string");
	decor->decorpincon_netname = copystr(schem_parse_state.string);
	t = rdschem_token();
	if (t != ';')
		goto syntaxerr;
	return(decor);
}

static struct decoration *
parse_decor_noconnect()
{
	register struct decoration *decor;
	register int t;

	decor = parser_alloc_decor(DECOR_TYPE_NOCONNECT);
	t = rdschem_token();
	if (t != STRING && t != QSTRING)
syntaxerr:	rdschem_error("(NoConnect decoration) syntax error");
	if (!schem_parse_state.string[0])
		rdschem_error("pin ID may not be a null string");
	if (!strcmp(schem_parse_state.string, "#"))
		rdschem_error("pin ID \"#\" is invalid");
	decor->decorpincon_pin = copystr(schem_parse_state.string);
	t = rdschem_token();
	if (t != ';')
		goto syntaxerr;
	return(decor);
}

static struct decoration *
parse_decor_symonpin()
{
	register struct decoration *decor;
	register int t;

	decor = parser_alloc_decor(DECOR_TYPE_SYMONPIN);
	t = rdschem_token();
	if (t != STRING && t != QSTRING)
syntaxerr:	rdschem_error("(SymOnPin decoration) syntax error");
	if (!schem_parse_state.string[0])
		rdschem_error("pin ID may not be a null string");
	if (!strcmp(schem_parse_state.string, "#"))
		rdschem_error("pin ID \"#\" is invalid");
	decor->decorpinsym_pin = copystr(schem_parse_state.string);
	t = rdschem_token();
	if (t != STRING && t != QSTRING)
		goto syntaxerr;
	if (!schem_parse_state.string[0])
		rdschem_error("graphical symbol name may not be a null string");
	decor->decorpinsym_symname = copystr(schem_parse_state.string);
	t = rdschem_token();
	if (t == STRING && !strcmp(schem_parse_state.string, "mirror")) {
		decor->decorpinsym_mirror = 1;
		t = rdschem_token();
	}
	if (t != ';')
		goto syntaxerr;
	return(decor);
}

static struct decoration *
parse_decor_graphblock(type)
{
	register int t;
	register struct decoration *decor;
	register struct graphblock *blk;

	t = rdschem_token();
	if (t != '{')
	    rdschem_error("GraphBlockG/GraphBlockPS must be followed by '{'");
	blk = rdschem_graphblock(type);
	decor = parser_alloc_decor(DECOR_TYPE_GRAPHBLOCK);
	decor->decorgraph_body = blk;
	schem_parse_state.schem->has_graphblocks = 1;
	return(decor);
}

static struct decoration *
parse_decor_comment()
{
	register int t;
	register struct decoration *decor;

	t = rdschem_token();
	if (t != STRING && t != QSTRING)
syntaxerr:	rdschem_error("(Comment decoration) syntax error");
	if (!schem_parse_state.string[0])
		rdschem_error("schematic comment may not be a null string");
	decor = parser_alloc_decor(DECOR_TYPE_COMMENT);
	decor->decorcomment_text = copystr(schem_parse_state.string);
	t = rdschem_token();
	if (t != ';')
		goto syntaxerr;
	return(decor);
}

struct decoration *
rdschem_parse_decor_block()
{
	struct decoration *decor, *head, **tailp;
	register int t;
	char errbuf[256];

	for (head = NULL, tailp = &head; ; ) {
		t = rdschem_token();
		switch (t) {
		case 0:
			rdschem_error("EOF in a decoration block");
		case '(':
			decor = parse_decor_attr();
			goto addit;
		case ';':
			/* "null statement" */
			continue;
		case '}':
			return(head);
		}
		if (t != STRING)
		    rdschem_error("syntax error: decoration keyword expected");
		if (!strcmp(schem_parse_state.string, "DisplayAttr"))
			decor = parse_decor_displayattr();
		else if (!strcmp(schem_parse_state.string, "DisplayNetName"))
			decor = parse_decor_displaynetname();
		else if (!strcmp(schem_parse_state.string, "PinToNet"))
			decor = parse_decor_pintonet();
		else if (!strcmp(schem_parse_state.string, "NoConnect"))
			decor = parse_decor_noconnect();
		else if (!strcmp(schem_parse_state.string, "SymOnPin"))
			decor = parse_decor_symonpin();
		else if (!strcmp(schem_parse_state.string, "GraphBlockG"))
			decor = parse_decor_graphblock(GRAPHBLOCK_TYPE_GSCHEM);
		else if (!strcmp(schem_parse_state.string, "GraphBlockPS"))
			decor = parse_decor_graphblock(GRAPHBLOCK_TYPE_PS);
		else if (!strcmp(schem_parse_state.string, "Comment"))
			decor = parse_decor_comment();
		else {
			sprintf(errbuf,
				"%s is not a recognized decoration keyword",
				schem_parse_state.string);
			rdschem_error(errbuf);
		}
addit:		*tailp = decor;
		tailp = &decor->decor_next;
	}
}

rdschem_parse_object()
{
	register int t;
	char errbuf[256];

	t = rdschem_token();
	if (!t)			/* EOF aka end of schematic */
		return(1);
	if (t == ';')		/* "null statement" */
		return(0);
	if (t != STRING)
		rdschem_error("syntax error: object keyword expected");

	if (!strcmp(schem_parse_state.string, "Component"))
		return(rdschem_parse_compinst());
	if (!strcmp(schem_parse_state.string, "GraphSym"))
		return(rdschem_parse_graphsym());
	if (!strcmp(schem_parse_state.string, "Net"))
		return(rdschem_parse_net());
	if (!strcmp(schem_parse_state.string, "GraphNet"))
		return(rdschem_parse_graphnet());
	if (!strcmp(schem_parse_state.string, "NetLine"))
		return(rdschem_parse_netline());
	if (!strcmp(schem_parse_state.string, "BusSeg"))
		return(rdschem_parse_busseg());
	if (!strcmp(schem_parse_state.string, "GraphBlockG"))
		return(rdschem_parse_graphblock_obj(GRAPHBLOCK_TYPE_GSCHEM));
	if (!strcmp(schem_parse_state.string, "GraphBlockPS"))
		return(rdschem_parse_graphblock_obj(GRAPHBLOCK_TYPE_PS));
	if (!strcmp(schem_parse_state.string, "Comment"))
		return(rdschem_parse_comment_obj());

	sprintf(errbuf, "%s is not a recognized object keyword",
		schem_parse_state.string);
	rdschem_error(errbuf);
}

rdschem_parse_compinst()
{
	register int t;
	register struct schemobj *obj;

	obj = parser_alloc_obj(OBJTYPE_COMPINST);
	t = rdschem_token();
	if (t != STRING && t != QSTRING)
syntaxerr:	rdschem_error("(Component object) syntax error");
	if (!schem_parse_state.string[0])
	    rdschem_error("component instance name may not be a null string");
	obj->compobj_instname = copystr(schem_parse_state.string);

	t = rdschem_token();
	if (t == STRING && !strcmp(schem_parse_state.string, "graph")) {
		obj->compobj_isgraph = 1;
		t = rdschem_token();
		if (t != STRING && t != QSTRING)
			goto syntaxerr;
		if (!schem_parse_state.string[0])
		rdschem_error("graphical symbol name may not be a null string");
		obj->compobj_graph_symname = copystr(schem_parse_state.string);
		obj->compobj_x = parse_number();
		obj->compobj_y = parse_number();
		t = rdschem_token();
		if (t == STRING && !strcmp(schem_parse_state.string, "rot")) {
			obj->compobj_rotate = parse_number();
			t = rdschem_token();
		}
		if (t == STRING && !strcmp(schem_parse_state.string, "mirror")){
			obj->compobj_mirror = 1;
			t = rdschem_token();
		}
	}

	if (t == '{') {
		obj->obj_decorations = rdschem_parse_decor_block();
		t = rdschem_token();
	}

	if (t != ';')
		goto syntaxerr;
	parser_add_object(obj);
	return(0);
}

rdschem_parse_graphsym()
{
	register int t;
	register struct schemobj *obj;

	obj = parser_alloc_obj(OBJTYPE_GRAPHSYM);
	t = rdschem_token();
	if (t != STRING && t != QSTRING)
syntaxerr:	rdschem_error("(GraphSym object) syntax error");
	if (!schem_parse_state.string[0])
		rdschem_error("graphical symbol name may not be a null string");
	obj->compobj_graph_symname = copystr(schem_parse_state.string);

	obj->compobj_x = parse_number();
	obj->compobj_y = parse_number();
	t = rdschem_token();
	if (t == STRING && !strcmp(schem_parse_state.string, "rot")) {
		obj->compobj_rotate = parse_number();
		t = rdschem_token();
	}
	if (t == STRING && !strcmp(schem_parse_state.string, "mirror")) {
		obj->compobj_mirror = 1;
		t = rdschem_token();
	}
	if (t == '{') {
		obj->obj_decorations = rdschem_parse_decor_block();
		t = rdschem_token();
	}

	if (t != ';')
		goto syntaxerr;
	parser_add_object(obj);
	return(0);
}

rdschem_parse_net()
{
	register int t;
	register struct schemobj *obj;
	register struct netpoint *netpt;
	struct netpoint *head, **tailp;

	obj = parser_alloc_obj(OBJTYPE_NET);
	t = rdschem_token();
	if (t != STRING && t != QSTRING)
syntaxerr:	rdschem_error("(Net object) syntax error");
	if (schem_parse_state.string[0])
		obj->netobj_netname = copystr(schem_parse_state.string);

	head = NULL;
	tailp = &head;
	for (;;) {
		t = rdschem_token();
		if (t == ';' || t == '{')
			break;
		if (t != STRING && t != QSTRING)
			goto syntaxerr;
		if (!schem_parse_state.string[0])
			goto syntaxerr;
		netpt = parser_alloc_netpoint(NETPT_TYPE_PIN);
		netpt->netpt_pin_nameref = copystr(schem_parse_state.string);
		*tailp = netpt;
		tailp = &netpt->netpt_next;
	}
	obj->netobj_points = head;

	if (t == '{') {
		obj->obj_decorations = rdschem_parse_decor_block();
		t = rdschem_token();
	}
	if (t != ';')
		goto syntaxerr;

	if (obj->netobj_points)
		parser_add_object(obj);
	else {
		fprintf(stderr, "%s: line %d: null Net object ignored\n",
			schem_parse_state.schem->orig_filename,
			schem_parse_state.lineno);
		free(obj);
	}
	return(0);
}

static struct xypair
parse_coord_pair()
{
	register int t;
	struct xypair retval;

	retval.x = parse_number();
	t = rdschem_token();
	if (t != ',')
syntaxerr:	rdschem_error("syntax error in coordinate pair");
	retval.y = parse_number();
	t = rdschem_token();
	if (t != ')')
		goto syntaxerr;
	return(retval);
}

static struct netpoint *
parse_graphnet_point()
{
	register int t;
	register struct netpoint *netpt;
	struct xypair coord_pair;

	t = rdschem_token();
	if (t == '(') {
		netpt = parser_alloc_netpoint(NETPT_TYPE_POINT);
		coord_pair = parse_coord_pair();
		netpt->netpt_x = coord_pair.x;
		netpt->netpt_y = coord_pair.y;
		netpt->netpt_coord_valid = 1;
		return(netpt);
	} else if (t == STRING && !strcmp(schem_parse_state.string, "Pin")) {
		netpt = parser_alloc_netpoint(NETPT_TYPE_PIN);
		t = rdschem_token();
		if (t == '(') {
			coord_pair = parse_coord_pair();
			netpt->netpt_x = coord_pair.x;
			netpt->netpt_y = coord_pair.y;
			netpt->netpt_coord_valid = 1;
			t = rdschem_token();
		}
		if (t == '=') {
			t = rdschem_token();
			if (t != STRING && t != QSTRING ||
			    !schem_parse_state.string[0])
		rdschem_error("syntax error: pin name reference expected");
			netpt->netpt_pin_nameref =
				copystr(schem_parse_state.string);
		} else if (netpt->netpt_coord_valid)
			schem_parse_state.pushback_token = t;
		else
			rdschem_error("syntax error: Pin must be followed by coordinates or name reference");
		return(netpt);
	} else if (t == STRING && !strcmp(schem_parse_state.string, "Tjoin")) {
		netpt = parser_alloc_netpoint(NETPT_TYPE_TJOIN);
		t = rdschem_token();
		if (t != '(')
	rdschem_error("syntax error: Tjoin must be followed by coordinates");
		coord_pair = parse_coord_pair();
		netpt->netpt_x = coord_pair.x;
		netpt->netpt_y = coord_pair.y;
		netpt->netpt_coord_valid = 1;
		return(netpt);
	} else if (t == STRING && !strcmp(schem_parse_state.string, "Pseudo")) {
		netpt = parser_alloc_netpoint(NETPT_TYPE_PSEUDO);
		t = rdschem_token();
		if (t != '(')
	rdschem_error("syntax error: Pseudo must be followed by coordinates");
		coord_pair = parse_coord_pair();
		netpt->netpt_x = coord_pair.x;
		netpt->netpt_y = coord_pair.y;
		netpt->netpt_coord_valid = 1;
		return(netpt);
	}
	schem_parse_state.pushback_token = t;
	return(NULL);
}

rdschem_parse_graphnet()
{
	register int t;
	register struct schemobj *obj;
	register struct netpoint *netpt;
	struct netpoint *head, **tailp;

	obj = parser_alloc_obj(OBJTYPE_GRAPHNET);
	t = rdschem_token();
	if (t != STRING && t != QSTRING)
syntaxerr:	rdschem_error("(GraphNet object) syntax error");
	if (schem_parse_state.string[0])
		obj->netobj_netname = copystr(schem_parse_state.string);

	head = NULL;
	tailp = &head;
	for (;;) {
		netpt = parse_graphnet_point();
		if (!netpt)
			break;
		*tailp = netpt;
		tailp = &netpt->netpt_next;
	}
	obj->netobj_points = head;

	t = rdschem_token();
	if (t == '{') {
		obj->obj_decorations = rdschem_parse_decor_block();
		t = rdschem_token();
	}
	if (t != ';')
		goto syntaxerr;

	if (obj->netobj_points)
		parser_add_object(obj);
	else {
		fprintf(stderr, "%s: line %d: null GraphNet object ignored\n",
			schem_parse_state.schem->orig_filename,
			schem_parse_state.lineno);
		free(obj);
	}
	return(0);
}

rdschem_parse_netline()
{
	register int t;
	register struct schemobj *obj;
	struct xypair coord_pair;

	obj = parser_alloc_obj(OBJTYPE_NETLINE);

	t = rdschem_token();
	if (t != '(')
syntaxerr:	rdschem_error("(NetLine object) syntax error");
	coord_pair = parse_coord_pair();
	obj->lineobj_x1 = coord_pair.x;
	obj->lineobj_y1 = coord_pair.y;
	t = rdschem_token();
	if (t != '(')
		goto syntaxerr;
	coord_pair = parse_coord_pair();
	obj->lineobj_x2 = coord_pair.x;
	obj->lineobj_y2 = coord_pair.y;

	t = rdschem_token();
	if (t == '{') {
		obj->obj_decorations = rdschem_parse_decor_block();
		t = rdschem_token();
	}
	if (t != ';')
		goto syntaxerr;
	parser_add_object(obj);
	return(0);
}

rdschem_parse_busseg()
{
	register int t;
	register struct schemobj *obj;
	struct xypair coord_pair;

	obj = parser_alloc_obj(OBJTYPE_BUSSEG);

	t = rdschem_token();
	if (t != '(')
syntaxerr:	rdschem_error("(BusSeg object) syntax error");
	coord_pair = parse_coord_pair();
	obj->lineobj_x1 = coord_pair.x;
	obj->lineobj_y1 = coord_pair.y;
	t = rdschem_token();
	if (t != '(')
		goto syntaxerr;
	coord_pair = parse_coord_pair();
	obj->lineobj_x2 = coord_pair.x;
	obj->lineobj_y2 = coord_pair.y;

	t = rdschem_token();
	if (t == '{') {
		obj->obj_decorations = rdschem_parse_decor_block();
		t = rdschem_token();
	}
	if (t != ';')
		goto syntaxerr;
	parser_add_object(obj);
	return(0);
}

rdschem_parse_graphblock_obj(type)
{
	register int t;
	register struct schemobj *obj;
	register struct graphblock *blk;

	t = rdschem_token();
	if (t != '{')
	    rdschem_error("GraphBlockG/GraphBlockPS must be followed by '{'");
	blk = rdschem_graphblock(type);
	obj = parser_alloc_obj(OBJTYPE_GRAPHBLOCK);
	obj->graphblockobj_body = blk;
	parser_add_object(obj);
	schem_parse_state.schem->has_graphblocks = 1;
	return(0);
}

rdschem_parse_comment_obj()
{
	register int t;
	register struct schemobj *obj;

	t = rdschem_token();
	if (t != STRING && t != QSTRING)
syntaxerr:	rdschem_error("(Comment object) syntax error");
	if (!schem_parse_state.string[0])
		rdschem_error("schematic comment may not be a null string");
	obj = parser_alloc_obj(OBJTYPE_COMMENT);
	obj->commentobj_text = copystr(schem_parse_state.string);
	t = rdschem_token();
	if (t != ';')
		goto syntaxerr;
	parser_add_object(obj);
	return(0);
}

static int
parse_number()
{
	register int t;
	char errbuf[256];

	t = rdschem_token();
	if (t != STRING)
		rdschem_error("syntax error (number expected)");
	if (!string_is_valid_decnum(schem_parse_state.string)) {
		sprintf(errbuf, "\"%s\" is not a valid decimal number",
			schem_parse_state.string);
		rdschem_error(errbuf);
	}
	return(atoi(schem_parse_state.string));
}