/*
* Copyright (c)2004-2010 Cat's Eye Technologies. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Cat's Eye Technologies nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* scan.c
* Lexical scanner for 2Iota.
* $Id: scan.c 518 2010-04-28 17:48:38Z cpressey $
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "scan.h"
#include "2iota.h"
struct scan_st *
scan_open(char *filename)
{
struct scan_st *sc;
MALLOC(sc, scan_st, "scanner");
if ((sc->token = (char *)malloc(256 * sizeof(char))) == NULL) {
free(sc);
return(NULL);
}
if ((sc->in = fopen(filename, "r")) == NULL) {
free(sc->token);
free(sc);
return(NULL);
}
sc->lino = 1;
sc->columno = 1;
scan(sc); /* prime the pump */
return(sc);
}
void
scan_close(struct scan_st *sc)
{
fclose(sc->in);
free(sc->token);
free(sc);
}
void
scan_error(struct scan_st *sc, const char *fmt, ...)
{
va_list args;
fprintf(stderr, "Error (line %d, column %d, token '%s'): ",
sc->lino, sc->columno, sc->token);
va_start(args, fmt);
vfprintf(stderr, fmt, args);
fprintf(stderr, ".\n");
}
static int
scan_char(struct scan_st *sc, char *x)
{
*x = (char)getc(sc->in); sc->columno++;
if (feof(sc->in)) {
sc->token[0] = 0;
return(0);
}
return(1);
}
void
scan(struct scan_st *sc)
{
char x;
int i = 0;
sc->token[0] = 0;
if (feof(sc->in)) return;
if (!scan_char(sc, &x)) return;
/* Skip whitespace. */
top:
while (isspace((int)x)) {
if (x == '\n') {
sc->lino++;
sc->columno = 0;
}
if (!scan_char(sc, &x)) return;
}
/* Skip comments. */
if (x == '/') {
while (x != '\n') {
if (!scan_char(sc, &x)) return;
}
goto top;
}
/*
* Scan decimal numbers. Must start with a
* digit (not a sign or decimal point.)
*/
if (isdigit((int)x) && !feof(sc->in)) {
while ((isdigit((int)x) || x == '.') && !feof(sc->in)) {
sc->token[i++] = x;
if (!scan_char(sc, &x)) return;
}
ungetc(x, sc->in);
sc->columno--;
sc->token[i] = 0;
return;
}
/* Scan alphanumeric tokens. */
if (isalpha((int)x) && !feof(sc->in)) {
while ((isalpha((int)x) || isdigit((int)x) || x == '_') && !feof(sc->in)) {
sc->token[i++] = x;
if (!scan_char(sc, &x)) return;
}
ungetc(x, sc->in);
sc->columno--;
sc->token[i] = 0;
return;
} else {
sc->token[0] = x;
sc->token[1] = 0;
return;
}
}
void
scan_expect(struct scan_st *sc, const char *x)
{
if (!strcmp(sc->token, x)) {
scan(sc);
} else {
scan_error(sc, "Expected '%s'", x);
}
}