223 lines
4.8 KiB
C
223 lines
4.8 KiB
C
//-----------------------------------------------------------------------------
|
|
//
|
|
// Copyright © 2016 David P. Hill & Project Golan
|
|
//
|
|
// This file contains material copyrighted by David P. Hill, licensed under
|
|
// the same GPLv2 license as Project Golan's code.
|
|
//
|
|
// See "LICENSE" for more information.
|
|
//
|
|
// This file also contains material copyrighted by David P. Hill licensed
|
|
// under the Lesser GPL license.
|
|
//
|
|
// See "COPYLIB" for more information.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// Token stream.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include "Lth.h"
|
|
|
|
|
|
// Type Definitions ----------------------------------------------------------|
|
|
|
|
//
|
|
// Lth_TokenStreamBuf
|
|
//
|
|
typedef struct Lth_TokenStreamBuf
|
|
{
|
|
char *beg, *itr, *end;
|
|
size_t len;
|
|
int (*getc)(struct Lth_TokenStreamBuf *);
|
|
int (*bumpc)(struct Lth_TokenStreamBuf *);
|
|
} Lth_TokenStreamBuf;
|
|
|
|
|
|
// Static Functions ----------------------------------------------------------|
|
|
|
|
//
|
|
// Lth_TokenFileStream_getc
|
|
//
|
|
static int Lth_TokenFileStream_getc(Lth_TokenStreamBuf *cookie)
|
|
{
|
|
if(cookie->itr == cookie->end) return EOF;
|
|
return *cookie->itr;
|
|
}
|
|
|
|
//
|
|
// Lth_TokenFileStream_bumpc
|
|
//
|
|
static int Lth_TokenFileStream_bumpc(Lth_TokenStreamBuf *cookie)
|
|
{
|
|
if(cookie->itr == cookie->end) return EOF;
|
|
return *cookie->itr++;
|
|
}
|
|
|
|
//
|
|
// Lth_TokenFileStream_read
|
|
//
|
|
static ssize_t Lth_TokenFileStream_read(void *cookie_, char *buf, size_t size)
|
|
{
|
|
Lth_TokenStreamBuf *cookie = cookie_;
|
|
size_t avail = cookie->end - cookie->itr;
|
|
|
|
if(size > avail)
|
|
size = avail;
|
|
|
|
if(size == 0) return 0;
|
|
|
|
for(ssize_t i = 0; i < size;)
|
|
{
|
|
if(cookie->getc(cookie) == '/')
|
|
{
|
|
cookie->bumpc(cookie);
|
|
if(cookie->getc(cookie) == '*')
|
|
{
|
|
for(cookie->bumpc(cookie); !(cookie->bumpc(cookie) == '*' && cookie->getc(cookie) == '/');)
|
|
if(cookie->getc(cookie) == EOF)
|
|
return i;
|
|
buf[i++] = ' ';
|
|
continue;
|
|
}
|
|
else if(cookie->getc(cookie) == '/')
|
|
{
|
|
do if(cookie->bumpc(cookie) == EOF) return i;
|
|
while(cookie->getc(cookie) != '\n');
|
|
buf[i++] = ' ';
|
|
continue;
|
|
}
|
|
else
|
|
buf[i++] = '/';
|
|
}
|
|
else if(cookie->getc(cookie) == EOF)
|
|
return i;
|
|
else
|
|
buf[i++] = cookie->bumpc(cookie);
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
//
|
|
// Lth_TokenFileStream_close
|
|
//
|
|
static int Lth_TokenFileStream_close(void *cookie_)
|
|
{
|
|
Lth_TokenStreamBuf *cookie = cookie_;
|
|
free(cookie);
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Lth_TokenFileStreamOpen
|
|
//
|
|
static FILE *Lth_TokenFileStreamOpen(void *data, size_t size)
|
|
{
|
|
cookie_io_functions_t io_funcs = {
|
|
.read = Lth_TokenFileStream_read,
|
|
.write = NULL,
|
|
.seek = NULL,
|
|
.close = Lth_TokenFileStream_close
|
|
};
|
|
|
|
Lth_TokenStreamBuf *cookie = calloc(1, sizeof(Lth_TokenStreamBuf));
|
|
|
|
cookie->beg = data;
|
|
cookie->itr = data;
|
|
cookie->end = cookie->beg + size;
|
|
cookie->getc = Lth_TokenFileStream_getc;
|
|
cookie->bumpc = Lth_TokenFileStream_bumpc;
|
|
|
|
return fopencookie(cookie, "r", io_funcs);
|
|
}
|
|
|
|
//
|
|
// Lth_TokenStreamGrab
|
|
//
|
|
static void Lth_TokenStreamGrab(Lth_TokenStream *stream)
|
|
{
|
|
if(feof(stream->fp)) return;
|
|
|
|
do Lth_TokenGet(stream->fp, &stream->tokbuf);
|
|
while((stream->skipspc && stream->tokbuf.type == Lth_TOK_Space) ||
|
|
(stream->skipeol && stream->tokbuf.type == Lth_TOK_LnEnd));
|
|
|
|
stream->filled = true;
|
|
}
|
|
|
|
|
|
// Extern Functions ----------------------------------------------------------|
|
|
|
|
//
|
|
// Lth_TokenStreamOpen
|
|
//
|
|
Lth_TokenStream *Lth_TokenStreamOpen(void *data, size_t size)
|
|
{
|
|
Lth_TokenStream *stream = calloc(1, sizeof(Lth_TokenStream));
|
|
|
|
stream->fp = Lth_TokenFileStreamOpen(data, size);
|
|
|
|
if(stream->fp == NULL)
|
|
{
|
|
free(stream);
|
|
return NULL;
|
|
}
|
|
|
|
stream->skipeol = stream->skipspc = true;
|
|
|
|
return stream;
|
|
}
|
|
|
|
//
|
|
// Lth_TokenStreamClose
|
|
//
|
|
void Lth_TokenStreamClose(Lth_TokenStream *stream)
|
|
{
|
|
if(stream == NULL) return;
|
|
|
|
Lth_TokenCleanup(stream->tokbuf);
|
|
fclose(stream->fp);
|
|
free(stream);
|
|
}
|
|
|
|
//
|
|
// Lth_TokenStreamBump
|
|
//
|
|
Lth_Token const *Lth_TokenStreamBump(Lth_TokenStream *stream)
|
|
{
|
|
Lth_Token const *tok = Lth_TokenStreamPeek(stream);
|
|
return stream->filled = false, tok;
|
|
}
|
|
|
|
//
|
|
// Lth_TokenStreamPeek
|
|
//
|
|
Lth_Token const *Lth_TokenStreamPeek(Lth_TokenStream *stream)
|
|
{
|
|
static Lth_Token const eof = { .type = Lth_TOK_EOF };
|
|
|
|
if(!stream->filled && (Lth_TokenStreamGrab(stream), !stream->filled))
|
|
return &eof;
|
|
|
|
return &stream->tokbuf;
|
|
}
|
|
|
|
//
|
|
// Lth_TokenStreamDrop
|
|
//
|
|
bool Lth_TokenStreamDrop(Lth_TokenStream *stream, Lth_TokenType tt)
|
|
{
|
|
Lth_Token const *tok = Lth_TokenStreamPeek(stream);
|
|
|
|
if(tok->type == tt)
|
|
return Lth_TokenStreamBump(stream), true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// EOF
|