Commit 01c39158 authored by Joel K. Pettersson's avatar Joel K. Pettersson
Browse files

Disable lexer testing. Clean-ups and portability fixes.

Disable test lexer and re-enable normal output by default,
adding a #define switch in sgensys.h to switch between the
old parser and the test lexer.

Some clean-ups for the test lexer, symtab code, and
other parts of the program. Make the test lexer handle
line comment ('#'), and change its buffered reading to
make multiple character ungetting possible.

Portability fixes:
 * Makefile and linking: Correct sh syntax.
   Check in Makefile for three uname -s cases:
    - Linux
    - OpenBSD or NetBSD
    - other ("generic UNIX")
   Unbreaks building on FreeBSD and DragonFly.
   Also reorder linking CC args for portability.
 * ALSA: Add missing call to snd_pcm_drain().

Re-remove GNUmakefile and simply use Makefile.

Change log:
 * 2017-11-27: Some cleanups for lexer and symtab modules.
               Add debug #define for hash table in symtab.c
               (for testing collisions).
 * 2018-01-21: Make lexer handle line comments ('#').
               Source fix for ALSA.
               Correct Makefile sh syntax
               and reorder CC args for linking.
 * 2018-02-04: Fix program.c typo / memory init bug.
 * 2018-02-08: Only include LFLAGS addition
               for OpenBSD and NetBSD on those systems.
               Unbreaks building on FreeBSD and DragonFly.
 * 2018-02-12: Change buffered reading in the lexer.
 * 2018-02-13: Rearranging of and renamings in lexer code.
               Add debug #define for lexer (for silent-enough
               output to measure time to process file).
               Move debug #define switches to sgensys.h.
 * 2018-02-14: Disable lexer, re-enable parser and output.
               Insert #define switch in sgensys.h to toggle.
 * 2018-02-19: Replace a ';' with a ',' in heading comments.
 * 2018-02-22: Update COPYING file. (FSF link updates.)
 * 2018-05-01: Replace README with rewritten version from
               04-16. Similar to newer versions, but with
               references to added features removed.
 * 2018-09-19: In program.c, remove two unused functions,
               and two useless conditionals, one broken.
 * 2018-10-25: Fix parser string matching bug
               (not impacting the current uses).
 * 2019-01-19: Complete branch merging.
               Correct README wording in one place.
               Re-remove GNUmakefile and simply use Makefile.
parent 24bd724f
GNU LESSER GENERAL PUBLIC LICENSE
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
......@@ -164,11 +164,11 @@ apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
------------------------------------------------------------------------
==================================================================
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
......@@ -812,7 +812,7 @@ the "copyright" line and a pointer to where the full notice is found.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
......@@ -831,11 +831,11 @@ might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
<https://www.gnu.org/licenses/why-not-lgpl.html>.
CFLAGS=-std=gnu99 -W -Wall -O2 -ggdb -ffast-math
LFLAGS=-lm
LFLAGS_LINUX=$(LFLAGS) -lasound
LFLAGS_OSSAUDIO=$(LFLAGS) -lossaudio
OBJ=audiodev.o \
generator.o \
lexer.o \
mempool.o \
osc.o \
parser.o \
program.o \
sgensys.o \
symtab.o \
wavfile.o
all: sgensys
clean:
rm -f $(OBJ) sgensys
sgensys: $(OBJ)
@if [ `uname -s` == 'Linux' ]; then \
echo "Linking for Linux build (ALSA and OSS)."; \
$(CC) $(LFLAGS_LINUX) $(OBJ) -o sgensys; \
else \
echo "Linking for generic OSS build."; \
$(CC) $(LFLAGS_OSSAUDIO) $(OBJ) -o sgensys; \
fi
audiodev.o: audiodev.c audiodev_*.c sgensys.h audiodev.h
$(CC) -c $(CFLAGS) audiodev.c
generator.o: generator.c sgensys.h math.h osc.h program.h
$(CC) -c $(CFLAGS) generator.c
lexer.o: lexer.c sgensys.h symtab.h lexer.h math.h
$(CC) -c $(CFLAGS) lexer.c
mempool.o: mempool.c sgensys.h mempool.h
$(CC) -c $(CFLAGS) mempool.c
osc.o: osc.c sgensys.h math.h osc.h
$(CC) -c $(CFLAGS) osc.c
parser.o: parser.c sgensys.h math.h parser.h program.h
$(CC) -c $(CFLAGS) parser.c
program.o: program.c sgensys.h parser.h program.h
$(CC) -c $(CFLAGS) program.c
sgensys.o: sgensys.c sgensys.h audiodev.h wavfile.h
$(CC) -c $(CFLAGS) sgensys.c
symtab.o: symtab.c sgensys.h symtab.h mempool.h
$(CC) -c $(CFLAGS) symtab.c
wavfile.o: wavfile.c sgensys.h wavfile.h
$(CC) -c $(CFLAGS) wavfile.c
......@@ -19,12 +19,16 @@ clean:
rm -f $(OBJ) sgensys
sgensys: $(OBJ)
@if [ `uname -s` == 'Linux' ]; then \
echo "Linking for Linux build (ALSA and OSS)."; \
$(CC) $(LFLAGS_LINUX) $(OBJ) -o sgensys; \
@UNAME="`uname -s`"; \
if [ $$UNAME = 'Linux' ]; then \
echo "Linking for Linux (using ALSA and OSS)."; \
$(CC) $(OBJ) $(LFLAGS_LINUX) -o sgensys; \
elif [ $$UNAME = 'OpenBSD' ] || [ $$UNAME = 'NetBSD' ]; then \
echo "Linking for OpenBSD or NetBSD (using OSS)."; \
$(CC) $(OBJ) $(LFLAGS_OSSAUDIO) -o sgensys; \
else \
echo "Linking for generic OSS build."; \
$(CC) $(LFLAGS_OSSAUDIO) $(OBJ) -o sgensys; \
echo "Linking for generic UNIX (using OSS)."; \
$(CC) $(OBJ) $(LFLAGS) -o sgensys; \
fi
audiodev.o: audiodev.c audiodev_*.c sgensys.h audiodev.h
......
sgensys is the Sound GENeration SYStem, a sound synthesis program developed
to be usable for musical purposes, as well as capable of generating all manner
of sounds; it will read a script file of its SGS (Sound Generation Script)
format and produce audio output, either sent to the audio device or, if
specified, written to a 16-bit PCM WAV file.
Script syntax overview:
Operators are oscillators that may be freely linked in any number of
configurations as carriers and modulators, each having a number of parameters.
They, along with their timing relative to each other, are the main objects
described by the script syntax.
When specified - or later referenced - operators are optionally followed by
arguments for their parameters. Other kinds of modifiers also exist that affect
operators but having other syntactical rules; such are used to affect the
relative timing of operators and their changes. These changes - including
setting the initial state - can be seen as events, each having its specific
target as well as location in time.
A new event terminates the previous one. On the topmost script scope, newlines
also terminate events; within sub-scopes, however, newlines may be placed
freely. This means that multiple events may be placed on one line - and that,
in short, it is always possible to omit newlines, but not to insert them
everywhere.
Whitespace is not allowed within multi-character names, keywords or numbers.
Apart from this, spaces and tabs may be freely placed, or - not recommended -
omitted.
When a numerical expression is given, specifying it within parentheses will
make the syntax freer, allowing whitespace to be freely placed; outside
parentheses, whitespace will mark the end of the expression.
The following main keywords - and sub-keywords - are supported:
S:
Set argument defaults and parameter modifiers. (referred to as
S default values)
f, r, t Set default values for parameters f (default 100),
r (default 1), t (default 1).
a Sets a multiplier for the amplitude for all non-modulator
waves; effectively a volume control for the combined output.
n Sets A4 tuning (default 444) for frequencies specified as
notes.
Osin, Osrs, Otri, Osqr, Osaw:
Specify operator - and if top-level, play - with wave type set to
either sine, square root of sine, triangle, square or saw wave.
When specified or later referenced, operators support the
following parameters:
t Time duration in seconds. If no t setting is given, the time
set depends on the context.
If there are several operators simultaneously given
(ie. in succession, ending with the next |), the time, where
not otherwise determined, is fitted to the combined duration of
their play; otherwise, the S default value is used. (t* can
also be used to specify this explicitly)
For nested operators, ie. modulators, the default time
is infinite (can also be given as ti), meaning they play
whenever a carrier they are linked to does. Infinite duration
is only supported for nested operators, all scripts having
finite duration.
sgensys is the Sound GENeration SYStem, a sound synthesis program
developed to be usable for musical purposes, as well as capable of
generating all manner of sounds. It reads script files of its SGS
(Sound Generation Script) format and produces corresponding audio
output.
Various wave types are supported, as well as FM, PM (which is what
is commonly called FM in audio synthesis), and AM. There is no
support for the use of pre-recorded samples in synthesis.
Audio output support includes ALSA (on Linux), OSS (on BSDs,
and as a fallback on Linux), and writing 16-bit PCM WAV files.
Building and installing
=======================
There are currently no install scripts provided. The program can be
manually copied, along with example scripts, after building.
Building can be done using make and a C compiler, on Linux or a BSD.
There are no extra dependencies except, on Linux, the ALSA sound
library headers.
Licensing
=========
sgensys is distributed under the terms of the GNU Lesser General
Public License (LGPL), version 3 or later. See the file COPYING
for details.
The sound generation scripts included currently do not have any
explicit licensing. If needed in the future, some Creative Commons
license will be used. Feel free to re-use snippets in writing your
own scripts.
Script syntax overview
======================
General description
-------------------
The current syntax uses keywords followed by zero or more
parameters with arguments. Each main keyword provides an action,
either at run time (like a function call in other languages),
or at parse time (like a global script setting).
The most important keyword, "O" followed by a wavetype, adds an
operator. Operators are oscillators with parameters, and may be
connected as carriers and modulators. They, and the timing of their
running, make the core features of the scripting language.
Events and timing are central; each addition of an operator, or
later change to operator or voice parameters, is an event. Timing
modifiers may be used quite freely in the script to change the
relative time placement of events.
Keyword parameters may either be set (named, followed by writing
their argument(s)), or left out to use the previous value or a
default value. Some default values can be changed using the "S"
(set option) parse-time action.
Modifiers are similar to keywords, but simpler and more flexible
in how they may be used. They may or may not be followed by an
argument (e.g. a delay time).
Keywords
--------
Each of these keywords is further described in its own section below.
S Set option (parameter default value or other);
runs during parsing.
O Add operator; an oscillator with parameters, either a
carrier which produces sound for a duration, or a
modulator; the "O" must be immediately followed by the
(initial) wave type, as in "Osin".
P Panning for the voice at the current location; to be
followed by the new value.
Q Quit script; end parsing, turning all that follows
into a comment. (Optional.) Other ways to comment exist.
See the section 'Timing' for modifiers.
Set option: S
-------------
Set parameter default value or other option; runs during parsing.
Usage: "S", followed by zero or more parameters, each with a value.
Parameters:
f Set default O "f" (frequency, Hz) value; defaults to 444.
r Set default O "r" (frequency ratio) value; defaults to 1.
t Set default O "t" (time, seconds) value; defaults to 1.
a Set multiplier for O "a" (amplitude) value applied to all
top-level carriers; defaults to 1.
n Sets A4 tuning (Hz) for O "f" (frequency, Hz) value using
note syntax; defaults to 444.
Operator: O (followed by wave type)
-----------------------------------
Add operator. If a carrier and not a modulator, adds sound at current time
position, playing for the time duration.
Usage: "O" followed by (initial) wave type (e.g. "Osin"), followed by zero
or more parameters, each with a value.
Wave types:
sin Sine.
sqr Square (naive).
tri Triangle (naive).
saw Saw (naive, decreasing).
srs Square root of sine (mirrored for the negative half);
a softer alternative to a square wave.
Parameters:
t Time duration in seconds. If no t setting is given, the
time set depends on the context.
For a single non-nested operator, 1 is used unless
the default value is changed with "S t".
When several operators are specified at the same
time and time is explicitly set for at least one, the
default time is the combined duration of their play.
(t* can also be used to specify this explicitly.)
For nested operators, i.e. modulators, the default
time is infinite (can also be set as "ti"), meaning they
play whenever a carrier they are linked to does. Infinite
duration is only supported for nested operators, all scripts
having finite duration.
For a composite event, the first part is given the
S default value if none set. The following parts will each in
turn be given the value of the preceding part if not explicitly
set - with the exception for nested operators of the last
part, which will have infinite time (ti) by default.
f Frequency in Hz. Notes may also be specified in justly intoned
C-major scale; optional subnote (c, d, e, f, g, a or b) inside
inner octave (between note and next note), then note (C, D, E,
F, G, A or B), then optionally s (sharp) or f (flat), then
optionally (default 4) the octave of the note (0-10).
S default value if none set. The following parts will each
in turn be given the value of the preceding part if not
explicitly set - with the exception of nested operators for
the last part, which will have infinite time (ti) by default.
f Frequency in Hz.
Gradual value adjustment also supported; see section.
f!<> Second frequency in Hz to modulate (FM) to by wave or envelope,
and/or a list of modulators given within the <> following the
number if given. This list replaces any previous FM modulators
set, and may be empty.
The per-sample product of the modulator amplitudes is
used to frequency-modulate the carrier(s), be they the final
f!<> A second frequency in Hz may follow the "!", for a range to
use with FM by wave or envelope. A list of modulator
operators may be specified within "<>"; this list replaces
any previous FM modulators set, and may be empty.
The product of the modulator amplitudes is used to
frequency-modulate the carrier(s), be they the final
carrier(s) or in turn modulator(s) for one or more other
carrier(s).
r Frequency ratio (modulator waves only) of carrier to modulator.
Keeps frequency that of the carrier divided by the given
number. Often used in the form r(n/m) to give an n:m ratio.
r (For modulator operators only.) Frequency ratio of carrier
to modulator. Keeps frequency that of the carrier divided by
the given number. May be used in the form r(n/m) for an
n:m ratio.
Gradual value adjustment also supported; see section.
r!<> Second frequency ratio (modulator waves only) to modulate (FM)
to by wave or envelope, and/or a list of modulators given
within the <> following the number if given. This list
r!<> (For modulator operators only.) A second frequency ratio,
for a range to use with FM by wave or envelope. A list of
modulator operators may be specified within "<>"; this list
replaces any previous FM modulators set, and may be empty.
The per-sample product of the modulator amplitudes is
used to frequency-modulate the carrier(s), be they the final
The product of the modulator amplitudes is used to
frequency-modulate the carrier(s), be they the final
carrier(s) or in turn modulator(s) for one or more other
carrier(s).
a Amplitude, where 1.0 gives a level of 0dB, which is the signal
max of the output. For a modulator wave, this however simply
adjusts the effect strength.
a Amplitude, where 1.0 corresponds to a level of 0dB. (Note
that for top-level carriers, the "S a" value is used as a
multiplier. Panning will also reduce the output level
unless at the extreme left or right.)
Gradual value adjustment also supported; see section.
a!<> Second amplitude to modulate (AM) to by wave or envelope,
and/or a list of modulators given within the <> following the
number if given. This list replaces any previous AM modulators
set, and may be empty.
The per-sample product of the modulator amplitudes is
used to amplitude-modulate the carrier(s), be they the final
a!<> A second amplitude may follow the "!", for a range to use
with AM by wave or envelope. A list of modulator operators
may be specified within "<>"; this list replaces any
previous AM modulators set, and may be empty.
The product of the modulator amplitudes is used to
amplitude-modulate the carrier(s), be they the final
carrier(s) or in turn modulator(s) for one or more other
carrier(s).
p Set the beginning phase of the wave. For example, p(3/4) will
make a sine or triangle wave begin at its "bottom". This is
mostly used where wanted for waves used by f!/r! or a!.
p!<> A list of modulator (PM) operators follow within the <>. This
list replaces any previous PM modulators set, and may be empty.
The per-sample sum of the modulator amplitudes is used
to phase-modulate the carrier(s), be they the final carrier(s)
p!<> A list of PM modulator operators may be specified within "<>";
this list replaces any previous PM modulators set, and may be
empty.
The sum of the modulator amplitudes is used to
phase-modulate the carrier(s), be they the final carrier(s)
or in turn modulator(s) for one or more other carrier(s).
s Silent time before playing, time in seconds.
Works like adding a delay, except it only affects this
operator.
w Set (change) wave type (sin, srs, tri, sqr, saw).
w Set (change) wave type. See list of wave types for values.
P:
Set the panning (left-right "balance") of the voice associated with
the present operator(s), affecting the mixing of all its operators.
Value ranges 0 (left) to 1 (right). Default is 0.5 (center).
Gradual value adjustment also supported; see section.
Panning: P
----------
Set the panning (left-right "balance") of the voice associated with
the present operator(s), affecting the left and right output levels.
Value range is 0 (all-left) to 1 (all-right). Default is 0.5 (center).
Panning not at either extreme end will reduce level.
Gradual value adjustment also supported; see section.
Quit: Q
-------
Quit script; end parsing, turning all that follows into a comment.
(Optional.)
Generally, comments are added using "#" (line comment) instead.
Values and expressions
----------------------
Whitespace is not allowed within multi-character names, keywords or
numbers, and separates values. Spaces and tabs may otherwise be used or
omitted anywhere.
The following other modifiers are supported:
\ Delay the next event and all following ones, time in seconds.
Alternatively, \t will delay by the time of the previous
event.
| Add (independently of \) just enough delay to make the next
event(s) begin at the expiration of all that preceeds it,
though \ may further delay it.
Following a "#", the rest of a line is commented out.
Numerical expressions are allowed within parentheses, allowing numbers
to be specified using basic arithmetic and freely placed whitespace.
Gradual value adjustment:
Some parameters are noted to support this. Instead of typing the
......@@ -137,30 +216,58 @@ Gradual value adjustment:
(square brackets):
v Target value.
t Time to reach target value.
c Character of gradual change; either lin, exp or log. (exp and
log are ear-tuned approximations designed to sound natural,
and symmetric to one another. these approximations allow
definite, finite timing, whereas a real exponential
calculation wouldn't)
c Change type; either lin, exp or log. (exp and log use
ear-tuned polynomial approximations designed to sound
natural, and which are symmetric to one another.)
Parameters and operator binding:
When specifying or referencing operators within {} brackets, any
parameters set following the closing '}' will be bound to and apply
to all of them.
Significantly, this allows multiple carriers (given within
the {}) to be linked to the same modulator(s), whether for FM, PM,
or AM. (Note: Support for this is experimental and incomplete.)
Labels and referencing:
Any operator when specified may be prefixed by "'label " in order to
define a label for it, where the label is anything followed by
Any operator when specified may be prefixed by "'label " in order
to define a label for it, where the label is anything followed by
whitespace; thereafter the label may be referenced as ":label",
allowing future changes to be placed at any later point in the script.
allowing future changes to be placed at any later point in the
script.
Parameters and operator binding:
When specifying or referencing operators within {} brackets, any
arguments that follow the closing '}' will be bound to and apply to all
of them.
Significantly, this allows multiple carriers (given within the
{}) to be linked to the same modulator(s), whether for FM, PM, or AM.
Frequencies as notes:
Frequency values may be specified as notes. Currently,
justly intoned C-major scale is supported; "S n" sets
the A4 tuning (default 444Hz). The value consists of the
note (C, D, E, F, G, A or B), optionally given a prefix
and/or suffix. The prefix is an optional subnote (c, d,
e, f, g, a or b) inside an inner octave (between note and
next note). The suffix is an optional s (sharp) or
f (flat), and/or, in the last position, an octave number
(from 0-10, default 4).
Timing
------
A new event terminates the previous one, but they will have the same
placement in time unless a delay is added.
At the topmost script scope, newlines also terminate events; within
sub-scopes, however, newlines may be placed freely.
Timing modifiers:
| Time separator. Delays what follows by the duration of
prior events. This is independent of delay added
with "\".
\ Delay the next event and all following ones, time in
seconds. Alternatively, \t will delay by the time of the
last event.
Composite events:
Writing a ';' (on a new line or the same line) after an event will
allow specifying new arguments to apply at the end of the previous
duration; this can be repeated.
This makes it possible to write a sequence of events as if a
single "composite event", not having to insert delays that affect the
timing of events later written, thus increasing the flexibility of how
changes to operators may be positioned in a script.
allow specifying new parameter arguments to apply at the end of the
previous duration; this can be repeated.
This makes it possible to write a sequence of events as if
a single "composite event", not having to insert delays that affect
the timing of events later written, thus increasing the flexibility
of how changes to operators may be positioned in a script.
......@@ -2,7 +2,7 @@
*
* This file and the software of which it is part is distributed under the
* terms of the GNU Lesser General Public License, either version 3 or (at
* your option) any later version; WITHOUT ANY WARRANTY, not even of
* your option) any later version, WITHOUT ANY WARRANTY, not even of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* View the file COPYING for details, or if missing, see
......
......@@ -2,7 +2,7 @@
*
* This file and the software of which it is part is distributed under the
* terms of the GNU Lesser General Public License, either version 3 or (at
* your option) any later version; WITHOUT ANY WARRANTY, not even of
* your option) any later version, WITHOUT ANY WARRANTY, not even of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* View the file COPYING for details, or if missing, see
......
......@@ -3,7 +3,7 @@
*
* This file and the software of which it is part is distributed under the
* terms of the GNU Lesser General Public License, either version 3 or (at
* your option) any later version; WITHOUT ANY WARRANTY, not even of
* your option) any later version, WITHOUT ANY WARRANTY, not even of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* View the file COPYING for details, or if missing, see
......@@ -92,6 +92,7 @@ static inline void close_linux_audio_dev(SGSAudioDev *ad) {
return;
}
snd_pcm_drain(ad->ref.handle);
snd_pcm_close(ad->ref.handle);
free(ad);
}
......
......@@ -3,7 +3,7 @@
*
* This file and the software of which it is part is distributed under the
* terms of the GNU Lesser General Public License, either version 3 or (at
* your option) any later version; WITHOUT ANY WARRANTY, not even of
* your option) any later version, WITHOUT ANY WARRANTY, not even of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* View the file COPYING for details, or if missing, see
......
......@@ -2,7 +2,7 @@
*
* This file and the software of which it is part is distributed under the
* terms of the GNU Lesser General Public License, either version 3 or (at
* your option) any later version; WITHOUT ANY WARRANTY, not even of
* your option) any later version, WITHOUT ANY WARRANTY, not even of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* View the file COPYING for details, or if missing, see
......
/* sgensys script lexer module.
* Copyright (c) 2014 Joel K. Pettersson <joelkpettersson@gmail.com>
/* sgensys: script lexer module.
* Copyright (c) 2014, 2017-2018 Joel K. Pettersson
* <joelkpettersson@gmail.com>.
*
* This file and the software of which it is part is distributed under the
* terms of the GNU Lesser General Public License, either version 3 or (at
* your option) any later version; WITHOUT ANY WARRANTY, not even of
* your option) any later version, WITHOUT ANY WARRANTY, not even of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* View the file COPYING for details, or if missing, see
......@@ -18,25 +19,29 @@
#include <string.h>
#include <stdlib.h>
#define BUF_LEN BUFSIZ
#define BUFC_ERROR '\0'
#define BUFC_EOF 0xFF
#define STRING_MAX_LEN 1024
#define BUF_LEN (BUFSIZ << 1)
#define STRING_MAX_LEN 1024
struct SGSLexer {
uint8_t buf1[BUF_LEN],
buf2[BUF_LEN];
uint8_t *buf_start,
*buf_read,
*buf_eof;
uint8_t buf[BUF_LEN];
size_t read_pos;
size_t fill_pos;
uint8_t *read_exception;
FILE *file;
const char *filename;
SGSSymtab *symtab;
uint32_t line, line_pos;
uint32_t line_num, char_num;
SGSToken token;
uint8_t string[STRING_MAX_LEN];
};
/**
* Create SGSLexer for the given file and using the given symbol
* table.
*
* \return instance, or NULL on failure.
*/
SGSLexer *SGS_create_lexer(const char *filename, SGSSymtab *symtab) {
SGSLexer *o;
if (symtab == NULL) return NULL;
......@@ -45,106 +50,146 @@ SGSLexer *SGS_create_lexer(const char *filename, SGSSymtab *symtab) {
o = calloc(1, sizeof(SGSLexer));
if (o == NULL) return NULL;
o->buf_start = NULL;
o->buf_read = o->buf_start + BUF_LEN; /* trigger initialization */
o->file = file;
o->filename = filename;
o->symtab = symtab;
return o;
}
/**
* Destroy instance, also closing the file for which the SGSLexer