From 77d0e3dc66ecd3028914496e4c0084bcb1f8f7af Mon Sep 17 00:00:00 2001 From: mdw Date: Mon, 26 Jul 1999 23:24:33 +0000 Subject: [PATCH] Complete rewrite. Allow a list of character sources to enable changes during parsing of syntactic constructs. --- scan.c | 297 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- scan.h | 150 ++++++++++++++++++++++++++------- 2 files changed, 371 insertions(+), 76 deletions(-) diff --git a/scan.c b/scan.c index 808ef8f..506f98c 100644 --- a/scan.c +++ b/scan.c @@ -1,10 +1,10 @@ /* -*-c-*- * - * $Id: scan.c,v 1.1 1999/07/01 08:56:23 mdw Exp $ + * $Id: scan.c,v 1.2 1999/07/26 23:24:33 mdw Exp $ * * Character scanners * - * (c) 1999 Mark Wooding + * (c) 1999 Straylight/Edgeware */ /*----- Licensing notice --------------------------------------------------* @@ -29,8 +29,12 @@ /*----- Revision history --------------------------------------------------* * * $Log: scan.c,v $ - * Revision 1.1 1999/07/01 08:56:23 mdw - * Initial revision + * Revision 1.2 1999/07/26 23:24:33 mdw + * Complete rewrite. Allow a list of character sources to enable changes + * during parsing of syntactic constructs. + * + * Revision 1.1.1.1 1999/07/01 08:56:23 mdw + * Initial revision. * */ @@ -43,84 +47,281 @@ #include #include +#include #include "scan.h" -/*----- Main code ---------------------------------------------------------*/ +/*----- File scanner source -----------------------------------------------*/ + +/* --- File scanner block --- */ + +typedef struct fscan { + scansrc ss; + FILE *fp; + unsigned f; +} fscan; -/* --- Generic scanner setup --- */ +/* --- @scan@ --- */ -static void scan_init(scanner *sc, scan_ops *ops, const char *src) +static int fscan_scan(scansrc *ss) { - sc->ops = ops; - sc->line = 1; - sc->src = src; - dstr_create(&sc->d); + fscan *fs = (fscan *)ss; + int ch = getc(fs->fp); + if (ch == '\n') + fs->ss.line++; + return (ch); } -/* --- @argv@ scanner --- */ +/* --- @destroy@ --- */ -static int argv_scan(void *p) +static void fscan_destroy(scansrc *ss) { - scan_argvctx *c = p; - int ch; + fscan *fs = (fscan *)ss; + if (!(fs->f & SCF_NOCLOSE)) + fclose(fs->fp); + if (fs->f & SCF_FREENAME) + free(fs->ss.src); + DESTROY(fs); +} - if (c->ch != EOF) { - ch = c->ch; - c->ch = EOF; - } else if (*c->p) - ch = *c->p++; - else if (*c->pp) { - c->p = *c->pp++; - ch = '\n'; - } else - ch = EOF; +/* --- File scanner operations --- */ + +static scansrc_ops fscan_ops = { fscan_scan, fscan_destroy }; + +/* --- @scan_file@ --- * + * + * Arguments: @FILE *fp@ = pointer to file descriptor + * @char *name@ = pointer to source file name + * @unsigned f@ = flags + * + * Returns: A scanner source. + * + * Use: Creates a new scanner source for reading from a file. + */ + +scansrc *scan_file(FILE *fp, char *name, unsigned f) +{ + fscan *fs = CREATE(fs); + fs->ss.ops = &fscan_ops; + fs->ss.src = name; + fs->ss.line = 1; + fs->fp = fp; + fs->f = f; + return (&fs->ss); +} + +/*---- Argv scanner source ------------------------------------------------*/ + +/* --- Argv scanner block --- */ + +typedef struct avscan { + scansrc ss; + char **av; + char *p; +} avscan; + +/* --- @scan@ --- */ +static int avscan_scan(scansrc *ss) +{ + avscan *as = (avscan *)ss; + int ch; + if (!as->p) + ch = EOF; + else if ((ch = *as->p++) == 0) { + as->ss.line++; + as->p = *as->av++; + ch = '\n'; + } return (ch); } -static void argv_unscan(int ch, void *p) +/* --- @destroy@ --- */ + +static void avscan_destroy(scansrc *ss) { - scan_argvctx *c = p; - c->ch = ch; + avscan *as = (avscan *)ss; + DESTROY(as); } -void scan_argvinit(scan_argvctx *c, char **pp) +/* --- Argv scanner operations --- */ + +static scansrc_ops avscan_ops = { avscan_scan, avscan_destroy }; + +/* --- @scan_argv@ --- * + * + * Arguments: @char **av@ = pointer to argument array (null terminated) + * + * Returns: A scanner source. + * + * Use: Creates a new scanner source for reading from an @argv@ + * array. + */ + +scansrc *scan_argv(char **av) { - static struct scan_ops ops = { argv_scan, argv_unscan }; - c->p = *pp++; - c->pp = pp; - c->ch = EOF; - scan_init(&c->sc, &ops, ""); + avscan *as = CREATE(avscan); + as->ss.ops = &avscan_ops; + as->ss.src = ""; + as->ss.line = 1; + as->p = *av++; + as->av = av; + return (&as->ss); } -/* --- File scanner --- */ +/*----- End-of-file sentinel block ----------------------------------------*/ + +/* --- @scan@ --- */ -static int file_scan(void *p) +static int eof_scan(scansrc *ss) { - scan_filectx *c = p; - return (getc(c->fp)); + return (EOF); } -static void file_unscan(int ch, void *p) +/* --- @destroy@ --- */ + +static void eof_destroy(scansrc *ss) { - scan_filectx *c = p; - ungetc(ch, c->fp); + ; } -void scan_fileinit(scan_filectx *c, FILE *fp, const char *file) +/* --- Eof scanner operations --- */ + +static scansrc_ops eof_ops = { eof_scan, eof_destroy }; + +/* --- The end of file marker --- */ + +static scansrc scan_eof = { &scan_eof, &eof_ops, "", 0, EOF }; + +/*----- General scanner handling ------------------------------------------*/ + +/* --- @scan@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * + * Returns: Character read, or end-of-file. + * + * Use: Scans a character from a source of characters. + */ + +int scan(scanner *sc) +{ + int ch; + if (sc->head->pushback != EOF) { + ch = sc->head->pushback; + sc->head->pushback = EOF; + } else { + scansrc *ss = sc->head; + if (ss == &scan_eof) + ch = EOF; + else if ((ch = ss->ops->scan(ss)) == EOF) { + sc->head = ss->next; + if (sc->head == &scan_eof) + sc->tail = &sc->head; + ss->ops->destroy(ss); + ch = '\n'; + } + } + return (ch); +} + +/* --- @unscan@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * @int ch@ = character to unscan + * + * Returns: --- + * + * Use: Scans a character from a source of characters. + */ + +void unscan(scanner *sc, int ch) +{ + sc->head->pushback = ch; +} + +/* --- @scan_push@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * @scansrc *ss@ = souorce to push + * + * Returns: --- + * + * Use: Pushes a scanner source onto the front of the queue. + */ + +void scan_push(scanner *sc, scansrc *ss) { - static struct scan_ops ops = { file_scan, file_unscan }; - c->fp = fp; - scan_init(&c->sc, &ops, file); + ss->next = sc->head; + if (sc->head == &scan_eof) + sc->tail = &ss->next; + sc->head = ss; + ss->pushback = EOF; + ss->tok = 0; + ss->t = 0; } -/* --- Miscellaneous functions --- */ +/* --- @scan_add@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * @scansrc *ss@ = souorce to push + * + * Returns: --- + * + * Use: Adds a scanner source onto the end of the queue. + */ + +void scan_add(scanner *sc, scansrc *ss) +{ + ss->next = &scan_eof; + *sc->tail = ss; + sc->tail = &ss->next; + ss->pushback = EOF; + ss->tok = 0; + ss->t = 0; +} + +/* --- @scan_create@ --- * + * + * Arguments: @scanner *sc@ = scanner context to initialize + * + * Returns: --- + * + * Use: Initializes a scanner block ready for use. + */ + +void scan_create(scanner *sc) +{ + sc->head = &scan_eof; + sc->tail = &sc->head; + dstr_create(&sc->d); +} + +/* --- @scan_destroy@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner context + * + * Returns: --- + * + * Use: Destroys a scanner and all the sources attached to it. + */ -void scan_destroy(void *p) +void scan_destroy(scanner *sc) { - scanner *sc = p; + scansrc *ss = sc->head; + while (ss != &scan_eof) { + scansrc *sss = ss; + ss = ss->next; + if (sss->tok) + free(sss->tok); + sss->ops->destroy(sss); + } dstr_destroy(&sc->d); + if (scan_eof.tok) + free(scan_eof.tok); + scan_eof.tok = 0; + sc->head = &scan_eof; + sc->tail = &sc->head; } /*----- That's all, folks -------------------------------------------------*/ diff --git a/scan.h b/scan.h index f08fe01..eee6f61 100644 --- a/scan.h +++ b/scan.h @@ -1,10 +1,10 @@ /* -*-c-*- * - * $Id: scan.h,v 1.1 1999/07/01 08:56:23 mdw Exp $ + * $Id: scan.h,v 1.2 1999/07/26 23:24:33 mdw Exp $ * * Character scanners * - * (c) 1999 Mark Wooding + * (c) 1999 Straylight/Edgeware */ /*----- Licensing notice --------------------------------------------------* @@ -29,8 +29,12 @@ /*----- Revision history --------------------------------------------------* * * $Log: scan.h,v $ - * Revision 1.1 1999/07/01 08:56:23 mdw - * Initial revision + * Revision 1.2 1999/07/26 23:24:33 mdw + * Complete rewrite. Allow a list of character sources to enable changes + * during parsing of syntactic constructs. + * + * Revision 1.1.1.1 1999/07/01 08:56:23 mdw + * Initial revision. * */ @@ -49,43 +53,133 @@ /*----- Data structures ---------------------------------------------------*/ -/* --- A configuration scanner --- */ +/* --- A low-level scanner source --- */ + +typedef struct scansrc { + struct scansrc *next; /* Next one in the list */ + struct scansrc_ops *ops; /* Pointer to operations table */ + char *src; /* Name of this source */ + int line; /* Current line number */ + int pushback; /* Pushback character */ + char *tok; /* Token pushback */ + unsigned t; /* Token type pushback */ +} scansrc; + +/* --- Scanner source operations --- */ -typedef struct scan_ops { - int (*scan)(void */*p*/); /* Character scan function */ - void (*unscan)(int /*ch*/, void */*p*/); /* Character pushback function */ -} scan_ops; +typedef struct scansrc_ops { + int (*scan)(scansrc */*ss*/); /* Read another character */ + void (*destroy)(scansrc */*ss*/); /* Destroy an unwanted source */ +} scansrc_ops; + +/* --- A character scanner --- */ typedef struct scanner { - scan_ops *ops; /* Pointer to scanner operations */ - const char *src; /* Name of this source */ - int line; /* Current line number */ + scansrc *head, **tail; /* Scanner list head and tail */ int t; /* Token type */ dstr d; /* Current token value */ } scanner; -/*----- Scanners provided -------------------------------------------------*/ +/*----- Particular scanner types ------------------------------------------*/ + +/* --- @scan_file@ --- * + * + * Arguments: @FILE *fp@ = pointer to file descriptor + * @char *name@ = pointer to source file name + * @unsigned f@ = flags + * + * Returns: A scanner source. + * + * Use: Creates a new scanner source for reading from a file. + */ + +extern scansrc *scan_file(FILE */*fp*/, char */*name*/, unsigned /*f*/); + +#define SCF_NOCLOSE 1u +#define SCF_FREENAME 2u + +/* --- @scan_argv@ --- * + * + * Arguments: @char **av@ = pointer to argument array (null terminated) + * + * Returns: A scanner source. + * + * Use: Creates a new scanner source for reading from an @argv@ + * array. + */ + +extern scansrc *scan_argv(char **/*av*/); + +/*----- General scanner handling ------------------------------------------*/ + +/* --- @scan@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * + * Returns: Character read, or end-of-file. + * + * Use: Scans a character from a source of characters. + */ + +extern int scan(scanner */*sc*/); -/* --- The @argv@ scanner --- */ +/* --- @unscan@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * @int ch@ = character to unscan + * + * Returns: --- + * + * Use: Scans a character from a source of characters. + */ -typedef struct scan_argvctx { - scanner sc; /* Scanner base structure */ - char *p; /* Pointer to next character */ - char **pp; /* Pointer to next string */ - int ch; /* Pushback character */ -} scan_argvctx; +extern void unscan(scanner */*sc*/, int /*ch*/); -extern void scan_argvinit(scan_argvctx */*c*/, char **/*pp*/); +/* --- @scan_push@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * @scansrc *ss@ = souorce to push + * + * Returns: --- + * + * Use: Pushes a scanner source onto the front of the queue. + */ -/* --- The file scanner --- */ +extern void scan_push(scanner */*sc*/, scansrc */*ss*/); -typedef struct scan_filectx { - scanner sc; /* Scanner base structure */ - FILE *fp; /* Stream pointer */ -} scan_filectx; +/* --- @scan_add@ --- * + * + * Arguments: @scanner *sc@ = pointer to main scanner context + * @scansrc *ss@ = souorce to push + * + * Returns: --- + * + * Use: Adds a scanner source onto the end of the queue. + */ + +extern void scan_add(scanner */*sc*/, scansrc */*ss*/); + +/* --- @scan_create@ --- * + * + * Arguments: @scanner *sc@ = scanner context to initialize + * + * Returns: --- + * + * Use: Initializes a scanner block ready for use. + */ + +extern void scan_create(scanner */*sc*/); + +/* --- @scan_destroy@ --- * + * + * Arguments: @scanner *sc@ = pointer to scanner context + * + * Returns: --- + * + * Use: Destroys a scanner and all the sources attached to it. + */ -extern void scan_fileinit(scan_filectx */*c*/, - FILE */*fp*/, const char */*file*/); +extern void scan_destroy(scanner */*sc*/); /*----- That's all, folks -------------------------------------------------*/ -- 2.11.0