view dspanal/charparse.c @ 308:f8344bc4fd61

dspanal: char2coff utility written, compiles
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 28 Oct 2019 05:20:50 +0000
parents
children
line wrap: on
line source

/*
 * This module reads C char array files; it will be linked into programs
 * that do further processing.
 */

#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

/* lexer tokens */
#define	WORD		256
#define	NUMBER		257
#define	HEXBYTE		258

/* limits */
#define	MAXWORD		63
#define	MAXDIGITS	5

static char *parser_filename;
static FILE *parser_readF;
static int parser_lineno;
static char parser_read_word[MAXWORD+1];
static int parser_read_number;

static void
parse_error(msg)
	char *msg;
{
	fprintf(stderr, "%s line %d: %s\n", parser_filename, parser_lineno,
		msg);
	exit(1);
}

static
my_getchar()
{
	register int c;

	c = getc(parser_readF);
	if (c < 0)
		return(c);
	if (!isascii(c))
		parse_error("non-ASCII character");
	if (iscntrl(c) && c != '\n' && c != '\t')
		parse_error("invalid control character");
	return(c);
}

static void
handle_trad_comment()
{
	register int c, flag;

	for (flag = 0; ; ) {
		c = my_getchar();
		if (c < 0)
			parse_error("/* comment ends in EOF");
		if (c == '\n')
			parser_lineno++;
		if (c == '/' && flag)
			return;
		flag = (c == '*');
	}
}

static void
handle_line_comment()
{
	register int c;

	for (;;) {
		c = my_getchar();
		if (c < 0)
			parse_error("// comment ends in EOF");
		if (c == '\n') {
			parser_lineno++;
			return;
		}
	}
}

static void
handle_comment()
{
	int c;

	c = my_getchar();
	switch (c) {
	case '*':
		/* traditional C comment style */
		handle_trad_comment();
		return;
	case '/':
		/* new-fangled double slash comment style */
		handle_line_comment();
		return;
	default:
		parse_error("character after '/' is not '*' or '/'");
		exit(1);
	}
}

static void
handle_num_token(first_digit)
{
	register int c, n;

	parser_read_number = first_digit - '0';
	for (n = 1; ; n++) {
		c = my_getchar();
		if (!isdigit(c))
			break;
		parser_read_number *= 10;
		parser_read_number += c - '0';
	}
	if (c >= 0) {
		if (isalpha(c) || c == '_')
			parse_error(
			"digits followed by letters: neither word nor number");
		ungetc(c, parser_readF);
	}
	if (n > MAXDIGITS)
		parse_error("number is too long (MAXDIGITS exceeded)");
}

static int
decode_hex_digit(c)
	register int c;
{
	if (isdigit(c))
		return(c - '0');
	else if (isupper(c))
		return(c - 'A' + 10);
	else
		return(c - 'a' + 10);
}

static void
handle_hex_token()
{
	register int c, n;

	c = my_getchar();
	if (c != 'x' && c != 'X')
		parse_error("\'0\' not followed by \'x\'");
	parser_read_number = 0;
	for (n = 0; n < 2; n++) {
		c = my_getchar();
		if (!isxdigit(c))
			parse_error("0x not followed by two hex digits");
		parser_read_number <<= 4;
		parser_read_number += decode_hex_digit(c);
	}
}

static void
handle_word_token(first_char)
{
	register int c;
	register char *cp;
	register int len;

	cp = parser_read_word;
	*cp++ = first_char;
	for (len = 1; ; ) {
		c = my_getchar();
		if (!isalnum(c) && c != '_')
			break;
		if (len >= MAXWORD)
			parse_error("text token is too long");
		*cp++ = c;
		len++;
	}
	*cp = '\0';
	if (c < 0)
		return;
	ungetc(c, parser_readF);
}

static int
get_token()
{
	register int c;

loop:	c = my_getchar();
	switch (c) {
	case EOF:
		return(0);
	case ' ':
	case '\t':
		goto loop;
	case '\n':
		parser_lineno++;
		goto loop;
	case '/':
		handle_comment();
		goto loop;
	case ',':
	case ';':
	case '=':
	case '[':
	case ']':
	case '{':
	case '}':
		return(c);
	case '0':
		handle_hex_token();
		return(HEXBYTE);
	}
	if (isdigit(c)) {
		handle_num_token(c);
		return(NUMBER);
	}
	if (isalpha(c) || c == '_') {
		handle_word_token(c);
		return(WORD);
	}
	fprintf(stderr, "%s line %d: bad character \'%c\'\n", parser_filename,
		parser_lineno, c);
	exit(1);
}

unsigned
read_char_file(filename, outbuf, buflimit)
	char *filename;
	u_char *outbuf;
	unsigned buflimit;
{
	register int t;
	u_char *outptr;
	unsigned bytecnt;

	parser_filename = filename;
	parser_readF = fopen(parser_filename, "r");
	if (!parser_readF) {
		perror(parser_filename);
		exit(1);
	}
	parser_lineno = 1;
	t = get_token();
	if (t != WORD || strcmp(parser_read_word, "const"))
		parse_error("expected \"const\" keyword");
	t = get_token();
	if (t != WORD || strcmp(parser_read_word, "unsigned"))
		parse_error("expected \"unsigned\" keyword");
	t = get_token();
	if (t != WORD || strcmp(parser_read_word, "char"))
		parse_error("expected \"char\" keyword");
	t = get_token();
	if (t != WORD)
		parse_error("expected char array name");
	t = get_token();
	if (t != '[')
		parse_error("expected \'[\'");
	t = get_token();
	if (t == NUMBER)
		t = get_token();
	if (t != ']')
		parse_error("expected \']\'");
	t = get_token();
	if (t != '=')
		parse_error("expected \'=\'");
	t = get_token();
	if (t != '{')
		parse_error("expected \'{\'");
	/* get first hex byte */
	t = get_token();
	if (t != HEXBYTE)
		parse_error("expected first hex byte");
	outptr = outbuf;
	*outptr++ = parser_read_number;
	bytecnt = 1;
	for (;;) {
		t = get_token();
		if (t == '}')
			break;
		if (t != ',')
			parse_error("expected comma between bytes");
		t = get_token();
		if (t == '}')
			break;
		if (t != HEXBYTE)
			parse_error("expected next hex byte");
		if (bytecnt >= buflimit)
			parse_error("buffer limit exceeded");
		*outptr++ = parser_read_number;
		bytecnt++;
	}
	t = get_token();
	if (t != ';')
		parse_error("expected terminating \';\'");
	fclose(parser_readF);
	return bytecnt;
}