view ueda/libuschem/rdschem_lex.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

/*
 * token lexer for the schematic parser
 */

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

extern char *malloc();

extern struct schem_parse_state schem_parse_state;

static
my_getchar()
{
	register int c;

	c = getc(schem_parse_state.file);
	if (c < 0)
		return(c);
	if (!isascii(c)) {
		rdschem_error("non-ASCII character");
		exit(1);
	}
	if (iscntrl(c) && c != '\n' && c != '\t') {
		rdschem_error("invalid control character");
		exit(1);
	}
	return(c);
}

rdschem_token()
{
	register int c;
	register char *cp;
	register int len;
	static char delims[] = "\n\"%(),;={}";

	if (c = schem_parse_state.pushback_token) {
		schem_parse_state.pushback_token = 0;
		return(c);
	}
loop:	c = my_getchar();
	switch (c) {
	case EOF:
		return(0);
	case ' ':
	case '\t':
		goto loop;
	case '"':
		yylex_qstr();
		return(QSTRING);
	case '%':
		do
			c = my_getchar();
		while (c != EOF && c != '\n');
		if (c == EOF)
			return(0);
		/* FALL THRU */
	case '\n':
		schem_parse_state.lineno++;
		goto loop;
	case '(':
	case ')':
	case ',':
	case ';':
	case '=':
	case '{':
	case '}':
		return(c);
	}
	cp = schem_parse_state.string;
	*cp++ = c;
	for (len = 1; ; ) {
		c = my_getchar();
		if (c == EOF || c == ' ' || c == '\t')
			break;
		if (index(delims, c)) {
			ungetc(c, schem_parse_state.file);
			break;
		}
		if (len >= MAXSTRING)
			rdschem_error("text token is too long");
		*cp++ = c;
		len++;
	}
	*cp = '\0';
	return(STRING);
}

static
yylex_qstr()
{
	register int c;
	register char *cp;
	register int len;

	cp = schem_parse_state.string;
	for (len = 0; ; ) {
		c = my_getchar();
		if (c == EOF || c == '\n')
unterm:			rdschem_error("unterminated quoted string");
		if (c == '"')
			break;
		if (c == '\\') {
			c = my_getchar();
			if (c == EOF || c == '\n')
				goto unterm;
		}
		if (len >= MAXSTRING)
			rdschem_error("quoted string is too long");
		*cp++ = c;
		len++;
	}
	*cp = '\0';
}

struct graphblock *
rdschem_graphblock(type)
{
	struct graphblock *blk;
	register int c, n;

	blk = (struct graphblock *) malloc(sizeof(struct graphblock));
	if (!blk) {
		perror("malloc");
		exit(1);
	}
	blk->type = type;
	blk->lineno = schem_parse_state.lineno;
	c = my_getchar();
	if (c == EOF)
badeof:		rdschem_error("EOF in a graphical block");
	if (c == '\n')
		schem_parse_state.lineno++;
	else
		ungetc(c, schem_parse_state.file);
	blk->offset = ftell(schem_parse_state.file);

	for (n = 0; n >= 0; ) {
		c = my_getchar();
		switch (c) {
		case EOF:
			goto badeof;
		case '%':
			for (;;) {
				c = my_getchar();
				if (c == EOF)
					goto badeof;
				if (c == '\n')
					break;
			}
			/* FALL THRU */
		case '\n':
			schem_parse_state.lineno++;
			continue;
		case '(':
			skip_over_ps_string();
			continue;
		case ')':
			rdschem_error("unmatched \')\' in a graphical block");
		case '{':
			n++;
			continue;
		case '}':
			n--;
			continue;
		}
	}
	blk->length = ftell(schem_parse_state.file) - blk->offset - 1;
	return(blk);
}

static
skip_over_ps_string()
{
	register int c, n;

	for (n = 1; n > 0; ) {
		c = my_getchar();
		switch (c) {
		case EOF:
badeof:		      rdschem_error("EOF in a PS string in a graphical block");
		case '\n':
			schem_parse_state.lineno++;
			continue;
		case '(':
			n++;
			continue;
		case ')':
			n--;
			continue;
		case '\\':
			c = my_getchar();
			if (c == EOF)
				goto badeof;
			if (c == '\n')
				schem_parse_state.lineno++;
			continue;
		}
	}
}