Skip to content

Instantly share code, notes, and snippets.

@Chubek
Created October 20, 2023 17:37
Show Gist options
  • Save Chubek/3f1a2c13353b5484f307d97da1459e5e to your computer and use it in GitHub Desktop.
Save Chubek/3f1a2c13353b5484f307d97da1459e5e to your computer and use it in GitHub Desktop.
Sappy: A Macro Preprocessor Prototype

sapp.y or Sappy is a macro preprocessor defined in one file, but IT DOES NOT WORK. I have not tested it. I stopped working on it. I am just posting it to show to someone!

%{
#define _POSIX_C_SOURCE 2
#define _X_OPEN_SOURCE 500
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <string.h>
#include <regex.h>
#include <time.h>
#include <stdbool.h>
#include <sysexits.h>
#include <getopt.h>
#include <signal.h>
#include <readline/readline.h>
#include <readline/history.h>
#ifndef INNER_SYMTBL_MAX
#define INNER_SYMTBL_MAX 16
#endif
#define LOCAL static
#define INlINE static inline
LOCAL uin8t_t *SYMTBL[UINT16_MAX + 1][INNER_SYMTBL_MAX];
INLINE blank_symtbl(void)
{ memset(SYMTBL, 0, sizeof(SYMTBL); }
INLINE uint16_t djb2(uint8_t *id)
{
uint16_t hash = 0;
uint8_t chr;
while ((chr = *id++))
hash = (hash * 33) + chr;
return hash;
}
INLINE uint8_t *upsert(uint8_t *id, uint8_t *val)
{
uint16_t hash = djb2(id);
uint8_t inhash = hash % (INNER_SYMTBL_MAX);
if (!val)
return SYMTBL[hash - 1][inhash - 1];
else
SYMTBL[hash - 1][inhash - 1] = strndup(val, strlen(val));
return NULL:
}
INLINE void remove(uint8_t *id)
{
uint8_t **id = &upsert(id, NULL);
free(id);
}
INLINE void dump_symtbl(void)
{
uint32_t l = UINT16_MAX + 1;
while (--l)
{
uint16_t ll = INNER_SYMTBL_MAX;
while (--ll)
(SYMTBL[l][ll] ? free(SYMTBL[l]) : NULL);
}
}
LOCAL size_t STACKLEN = 4096;
LOCAL uint8_t *DEFN_STACK[STACKLEN];
LOCAL size_t SP = 0;
INLINE void push_stack(uint8_t *defn)
{ DEFN_STACK[SP++] = strdup(defn); SP >= STACKLEN ? (SP = 0) : NULL; }
INLINE uint8_t* pop_stack(void) { return DEFN_STACK[--SP]; }
INLINE void dump_stack(void) { while (SP) free(pop_stack()); }
LOCAL uint8_t *OUTPATH;
LOCAL FILE *OUTPUT, PUTPUT;
LOCAL FILE *PIPE;
LOCAL FILE *DIVERT_STREAM[NUM_DIVERT];
LOCAL FILE *NULL_STREAM;
LOCAL uint8_t *DIVERT_STRING[NUM_DIVERT];
LOCAL size_t DIVERT_LENGTHS[NUM_DIVERT];
LOCAL int LAST_EXIT_CODE;
LOCAL uint8_t *LAST_EXEC_RES;
LOCAL uint8_t **INVOKE_ARGS;
LOCAL size_t SSP = 0;
LOCAL size_t STATE_STACKLEN = 1024;
LOCAL struct LexState
{
uint8_t *macro_prefix;
uint8_t *macro_suffix;
uint8_t *macro_leftbrack;
uint8_t *macro_rightbrack;
uint8_t *macro_separator;
uint8_t *macro_finisher;
uint8_t *macro_argnumprefix;
uint8_t *macro_argexpansion;
uint8_t *macro_delimexpansion;
uint8_t *macro_expansiondelim;
uint8_t *macro_name;
uint8_t *comment_start;
uint8_t *comment_end;
uint8_t *quote_start;
uint8_t *quote_end;
uint8_t *escape_mark;
uint8_t *define_mark;
uint8_t *undefine_mark;
uint8_t *push_mark;
uint8_t *pop_mark;
uint8_t *eval_mark;
uint8_t *exec_mark;
uint8_t *echo_mark;
uint8_t *mode_mark;
uint8_t *divert_mark;
uint8_t *aux_mark;
uint8_t *if_mark;
uint8_t *else_mark;
uint8_t *param_mark;
uint8_t *reflect_mark;
uint8_t *repeat_mark;
uint8_t *delim_begin;
uint8_t *delim_end;
uint8_t *parse_delim;
}
LEX_STATE, *STATE_STACK[STATE_STACKLEN];
INLINE void push_state(void)
{
STATE_STACK[SSP] = calloc(sizeof(struct LexState));
memmove(&STATE_STACK[SSP++], &LEX_STATE, sizeof(struct LexState));
}
INLINE void set_state(void)
{ LEX_STATE = *STATE_STACK[--SSP]; }
#define MACRO_PREFIX "%MPX"
#define MACRO_SUFFIX "%MSX"
#define MACRO_LEFTBRACK "%LBR"
#define MACRO_RIGHTBRACK "%RBR"
#define MACRO_SEPARATOR "%SEP"
#define MACRO_FINISHER "%FIN"
#define MACRO_ARGNUMPREFIX "%NARG"
#define MACRO_ARGEXPANSION "%XARG"
#define MACRO_DELIMEXPANSION "%DARG"
#define MACRO_EXPANSIONDELIM "%XDLIM"
#define MACRO_NAME "%MNAME"
#define COMMENT_START "%CMS"
#define COMMENT_END "%CME"
#define QUOTE_START "%QS"
#define QUOTE_END "%QE"
#define DEFINE_MARK "%DEF"
#define UNDEFINE_MARK "%UNDEF"
#define PUSH_MARK "%PUSH"
#define POP_MARK "%POP"
#define MODE_MARK "%MODE"
#define AUX_MARK "%RUN"
#define ESCAPE_MARK "%ESC"
#define ECHO_MARK "%ECHO"
#define EVAL_MARK "%EVAL"
#define EXEC_MARK "%EXEC"
#define DIVERT_MARK "%DIVR"
#define REPEAT_MARK "%REPT"1
#define IF_MARK "%IF"
#define ELSE_MARK "%ELSE"
#define PARAM_MARK "%PARAM"
#define REFLECT_MARK "%REFL"
#define DELIM_BEGIN "%DBEG"
#define DELIM_END "%DEND"
#define PARSE_DELIM "%PDLIM"
#define MAX_TOKEN_LEN 32
#define MAX_FMT_LEN 8
LOCAL void config_state(char *token, uint8_t *set, bool f)
{
LOCAL uint8_t **refarr = {
&LEX_STATE.macro_prefix, MACRO_PREFIX,
&LEX_STATE.macro_suffix, MACRO_SUFFIX,
&LEX_STATE.macro_leftbrack, MACRO_LEFTBRACK,
&LEX_STATE.macro_rightbrack, MACRO_RIGHTBRACK,
&LEX_STATE.macro_separator, MACRO_SEPARATOR,
&LEX_STATE.macro_finisher, MACRO_FINISHER,
&LEX_STATE.macro_argexpansion, MACRO_ARGEXPANSION,
&LEX_STATE.macro_expansiondelim, MACRO_EXPANSIONDELIM,
&LEX_STATE.macro_argnumprefix, MACRO_ARGNUMPREFIX,
&LEX_STATE.macro_delimexpansion, MACRO_DELIMEXPANSION,
&LEX_STATE.macro_name, MACRO_NAME,
&LEX_STATE.comment_start, COMMENT_START,
&LEX_STATE.comment_end, COMMENT_END,
&LEX_STATE.quote_start, QUOTE_START,
&LEX_STATE.quote_end, QUOTE_END,
&LEX_STATE.escape_mark, ESCAPE_MARK,
&LEX_STATE.echo_mark, ECHO_MARK,
&LEX_STATE.define_mark, DEFINE_MARK,
&LEX_STATE.undefine_mark, UNDEFINE_MARK,
&LEX_STATE.push_mark, PUSH_MARK,
&LEX_STATE.pop_mark, POP_MARK,
&LEX_STATE.mode_mark, MODE_MARK,
&LEX_STATE.aux_mark, AUX_MARK,
&LEX_STATE.eval_mark, EVAL_MARK,
&LEX_STATE.exec_mark, EXEC_MARK,
&LEX_STATE.reflect_mark, REFLECT_MARK,
&LEX_STATE.repeat_mark, REPEAT_MARK,
&LEX_STATE.divert_mark, DIVERT_MARK,
&LEX_STATE.if_mark, IF_MARK,
&LEX_STATE.param_mark, PARAM_MARK,
&LEX_STATE.else_mark, ELSE_MARK,
&LEX_STATE.delim_begin, DELIM_BEGIN,
&LEX_STATE.delim_end, DELIM_END,
&LEX_STATE.parse_delim, PARSE_DELIM,
NULL, NULL,
};
uint8_t ***refptr = &refarr;
uint8_t **ref, *fmt;
for (ref = *refptr, fmt = *refptr++;
ref;
ref = *refptr++, fmt = *refptr++)
{
if (!strncmp(fmt, token, MAX_FMT_LEN))
{
f ? free(*ref) : NULL;
*ref = set ? strndup(set, MAX_TOKEN_LEN) : NULL;
return;
}
}
}
INLINE void exit_run(int reason)
{ exit(reason); }
INLINE void exec_system(uint8_t *cmd)
{ LAST_EXIT_CODE = system(cmd); }
LOCAL void exec_pipe(uint8_t *cmd)
{
PIPE = popen(cmd, "r");
size_t len;
fseek(PIPE, SEEK_END);
len = ftell(PIPE);
rewind(PIPE);
LAST_EXEC_RES = calloc(len, 1);
fgets(&LAST_EXEC_RES[0], len, PIPE);
fputs(LAST_EXEC_RES, OUTPUT);
free(LAST_EXEC_RES);
pclose(PIPE);
}
INLINE void divert(int num)
{
if (num < 0) { PUTPUT = OUTPUT; OUTPUT = NULL_STREAM; }
else { PUTPUT = OUTPUT; OUTPUT = DIVERT_STREAM[num]; }
}
INLINE void undivert(int num)
{
OUTPUT = PUTPUT;
if (num > 0)
{ fputs(DIVERT_STRING[num], OUTPUT); }
}
INLINE void open_diverts(void)
{ for (int i = NUM_DIVERTS - 1; i; --i)
DIVERT_STREAM[i] =
open_memstream(
&DIVERT_STING[i],
&DIVERT_LENGTHS[i]); }
INLINE void free_diverts(void)
{ for (int i = NUM_DIVERTS - 1; i; --i)
{ free(DIVERT_STRING[i]); fclose(DIVERT_STREAM[i]); }
}
INLINE void add_invoke_arg(uint8_t *arg)
{ static int ninvoke = 0; INVOKE_ARGS[ninvoke++] = strdup(arg); }
INLINE void free_invoke_args(void)
{ uint8_t *ia; while ((ia = *INVOKE_ARGS++)) free(ia); }
INLINE void print_fmt(uint8_t *fmt)
{ uint8_t c; while ((c = *fmt++)) {
if (c == '%' && *fmt != '%')
{
uint8_t fmt2[3] = {'%', c, 0};
uint8_t *arg = *INVOKE_ARGS++;
fprintf(OUTPUT, &fmt2[0], (uintptr_t)arg);
}
}
INLINE void translit(uint8_t *text, uin8t_t *map, uint8_t *mapto)
{
size_t i = 0;
uint8_t chr = 0;
size_t maplen = strlen(map);
size_t mtolen = strlen(mapto);
if (!maplen || !mtolen)
{
fprintf(stderr, "Translit needs two arguments");
exit(EXIT_FAILURE);
}
uint8_t trntable[256];
while ((chr = *map++))
trntable[chr] = *mapto++;
while ((chr = *text++))
fprintf(OUTPUT, "%c", trntable[chr]);
}
INLINE void index(uint8_t *text, uint8_t *sub)
{
fprintf(OUTPUT, "%lu", ((size_t)strstr(text, sub) - ((size_t)text)));
}
INLINE void include_file(uint8_t *path)
{
FILE *s = fopen(path, "r");
if (!s)
{
ferr:
perror("fopen");
exit(EX_IOERR);
}
fseek(s, -1, SEEK_END) < 0 ? goto ferr : NULL;
long len = ftell(s);
if (len < 0)
goto ferr;
rewind(s);
uint8_t *txt = calloc(len, 1);
if (!txt)
{
fpritnf(stderr, "Memory error\n");
exit(EXIT_FAILURE);
}
fread(&txt[0], len, 1, s);
fputs(&txt[0], s);
free(txt);
}
LOCAL uint16_t CURR_PATH_HASH = 0;
LOCAL FILE *CURR_FILE;
LOCAL uint8_t *CURR_LINE;
LOCAL size_t CURR_LEN;
INLINE void get_line(uint8_t *path, uint8_t *delim)
{
uint16_t hash = djb2(path);
if (CURR_PATH_HASH == hash)
{
getln:
!delim
? getline(&CURR_LINE, &CURR_LEN, CURR_FILE)
: getdelim(&CURR_LINE, &CURR_LEN, delim, CURR_FILE);
goto println;
}
else
{
CURR_PATH_HASH = hash;
CURR_FILE = fopen(path, "r");
if (!CURR_FILE)
{
perror("fopen");
exit(EX_IOERR);
}
goto getln;
}
println:
fputs(CURR_LINE, CURR_FILE);
free(CURR_LINE);
}
INLINE void close_file(void)
{ fclose(CURR_FILE); }
INLINE void print_date(uint8_t *fmt)
{
struct tm tmp;
time_t time;
t = time(NULL);
tmp = localtime(&t);
if (!tmp)
{
perror("localtime");
exit(EX_TEMPFAIL);
}
char out[512];
if (strftime(out, 512, fmt, tmp) == 0)
{
perror("strftime");
exit(EX_TEMPFAIL);
}
fputs(&out[0], OUTPUT);
}
LOCAL regex_t RE_CC;
LOCAL regmatch_t PMATCH[1];
INLINE void yyexpreval(uint8_t*);
typedef void (*callback_t)(uint8_t*);
LOCAL void matches_act_if(uint8_t *pattern,
uint8_t *str, uint8_t *main,
uint8_t *instead, callback_t cback)
{
if (regcomp(&RE_CC, pattern, REG_NOSUB) < 0)
{
perror("regex");
exit(EX_TEMPFAIL);
}
if (!regexec(&RE_CC, str, 1, PMATCH, 0))
{
cback(main);
}
else if (ins)
{
cback(instead);
}
regfree(&RE_CC);
}
LOCAL void unmatches_act_if(uint8_t *pattern,
uint8_t *str, uint8_t *main,
uint8_t *instead, callback_t cback)
{
if (regcomp(&RE_CC, pattern, REG_NOSUB) < 0)
{
perror("regex");
exit(EX_TEMPFAIL);
}
if (regexec(&RE_CC, str, 1, PMATCH, 0))
{
cback(main);
}
else if (ins)
{
cback(instead);
}
regfree(&RE_CC);
}
LOCAL void defined_act_if(uint8_t *id, uint8_t *cmd,
uint8_t *instead, callback_t cback)
{
if (upsert(id, NULL))
cback(str)
else if (ins)
cback(instead);
}
LOCAL void undefined_act_if(uint8_t *id, uint8_t *cmd,
uint8_t *instead, callback_t cback)
{
if (!upsert(id, NULL))
cback(str)
else if (ins)
cback(instead);
}
LOCAL void equals_act_if(uint8_t *id, uint8_t *eq, uint8_t *ifeq,
uint8_t *instead, callback_t cback)
{
uint8_t *sym = upsert(id);
if (!strncmp(eq, sym, strlen(eq)))
cback(ifeq);
else if (instead)
cback(instead);
}
LOCAL void unequals_act_if(uint8_t *id, uint8_t *eq, uint8_t *ifeq,
uint8_t *instead, callback_t cback)
{
uint8_t *sym = upsert(id);
if (strncmp(eq, sym, strlen(eq)))
cback(ifeq);
else if (instead)
cback(instead);
}
LOCAL void print_wrapper(uint8_t *str);
{ fputs(str, OUTPUT); }
INLINE void matches_print_if(uint8_t *pattern,
uint8_t *str, uint8_t *main, uint8_t *instead)
{ matches_act_if(pattern, str, main, instead, print_wrapper); }
INLINE void matches_exec_if(uint8_t *pattern,
uint8_t *str, uint8_t *main, uint8_t *instead)
{ matches_act_if(pattern, str, main, instead, exec_pipe); }
INLINE void matches_eval_if(uint8_t *pattern,
uint8_t *str, uint8_t *main, uint8_t *instead)
{ matches_act_if(pattern, str, main, instead, yyexpreval); }
INLINE void unmatches_print_if(uint8_t *pattern,
uint8_t *str, uint8_t *main, uint8_t *instead)
{ unmatches_act_if(pattern, str, main, instead, print_wrapper); }
INLINE void unmatches_exec_if(uint8_t *pattern,
uint8_t *str, uint8_t *main, uint8_t *instead)
{ unmatches_act_if(pattern, str, main, instead, exec_pipe); }
INLINE void unmatches_eval_if(uint8_t *pattern,
uint8_t *str, uint8_t *main, uint8_t *instead)
{ unmatches_act_if(pattern, str, main, instead, yyexpreval); }
INLINE void defined_print_if(uint8_t *id, uint8_t *txt,
uint8_t *instead)
{ defined_act_if(id, txt, instead, print_wrapper); }
INLINE void defined_exec_if(uint8_t *id, uint8_t *cmd,
uint8_t *instead)
{ defined_act_if(id, cmd, instead, exec_pipe); }
INLINE void defined_eval_if(uint8_t *id, uint8_t *expr,
uint8_t *instead)
{ defined_act_if(id, expr, instead, yyexpreval); }
INLINE void undefined_print_if(uint8_t *id, uint8_t *txt,
uint8_t *instead)
{ undefined_act_if(id, cmd, instead, print_wrapper); }
INLINE void undefined_exec_if(uint8_t *id, uint8_t *cmd,
uint8_t *instead)
{ undefined_act_if(id, txt, instead, exec_pipe); }
INLINE void undefined_eval_if(uint8_t *id, uint8_t *expr,
uint8_t *instead)
{ undefined_act_if(id, expr, instead, yyexpreval); }
INLINE void equals_print_if(uint8_t *id, uint8_t *txt,
uint8_t *instead)
{ equals_act_if(id, cmd, instead, print_wrapper); }
INLINE void equals_exec_if(uint8_t *id, uint8_t *cmd,
uint8_t *instead)
{ equals_act_if(id, txt, instead, exec_pipe); }
INLINE void equals_eval_if(uint8_t *id, uint8_t *expr,
uint8_t *instead)
{ equals_act_if(id, expr, instead, yyexpreval); }
INLINE void unequals_print_if(uint8_t *id, uint8_t *txt,
uint8_t *instead)
{ unequals_act_if(id, cmd, instead, print_wrapper); }
INLINE void unequals_exec_if(uint8_t *id, uint8_t *cmd,
uint8_t *instead)
{ unequals_act_if(id, txt, instead, exec_pipe); }
INLINE void unequals_eval_if(uint8_t *id, uint8_t *expr,
uint8_t *instead)
{ unequals_act_if(id, expr, instead, yyexpreval); }
INLINE void to_stderr(uint8_t *str)
{
uint8_t *prefix = getenv("SAPP_STDERR_PREFIX");
fputs(prefix, stderr);
fputs(str, stderr);
}
LOCAL uint8_t *DELIM_EXEC_CMD;
INLINE void set_delim_exec(uint8_t *cmd)
{ if (DELIM_EXEC_CMD) free(DELIM_EXEC_CMD); DELIM_EXEC_CMD = strdup(cmd); }
INLINE void delim_exec(uint8_t *input)
{
LOCAL uint8_t *tmpdir = getenv("SAPP_TMP_DIR");
if (!tmpdir)
tmpdir = P_tmpdir;
strncat(tmpdir, "/XXXXXXX_SAPP.input", 32);
if (mkstemp(tmpdir) < 0)
{
perror("mkstemp");
exit(EX_IOERR);
}
FILE *backup = stdin;
FILE *restdin = freopen(tmpdir, "rw", stdin);
fputs(input, restdin);
pipe_exec(DELIM_EXEC_CMD);
fclose(restdin);
stdin = backup;
}
LOCAL regex_t RE_IDENT;
LOCAL regex_t RE_STRING;
INLINE void compile_ident_re(uint8_t *pattern)
{
if (regcomp(&RE_IDENT, pattern, REG_NOSUB) < 0)
{
perror("regcomp");
exit(EX_TEMPFAIL);
}
}
INLINE bool match_ident(uint8_t *string)
{
return !regexec(&RE_IDENT, string, 1, NULL, 0);
}
INLINE void free_ident_re(void)
{ regfree(&RE_IDENT); }
INLINE void compile_string_re(uint8_t *pattern)
{
if (regcomp(&RE_STRING, pattern, REG_NOSUB) < 0)
{
perror("regcomp");
exit(EX_TEMPFAIL);
}
}
INLINE bool match_string(uint8_t *string)
{
return !regexec(&RE_STRING, string, 1, NULL, 0);
}
INLINE void free_ident_re(void)
{ regfree(&RE_STRING); }
LOCAL struct Expansion
{
uint8_t *id;
uint8_t *argv[ARG_MAX];
uint8_t *argv_joined;
uint8_t *argv_delim_joined;
size_t argc;
}
CURR_EXPANSION;
INLINE void yymacroeval(uint8_t *macro);
INLINE void free_expn(void)
{
if (!CURR_EXPANSION.id) return;
while (--CURR_EXPANSION.argc)
{ free(CURR_EXPANSION.argv[CURR_EXPANSION.argc]);}
free(CURR_EXPANSION.argv_joined);
free(CURR_EXPANSION.argv_delim_joined);
free(CURR_EXPANSION.id);
}
INLINE void blank_out_expn(void)
{ memset(&CURRENT_EXPANSION, 0, sizeof(struct Expansion)); }
INLINE void set_expn_ident(uint8_t *ident)
{ CURR_EXPANSION.id = strdup(ident); }
INLINE void add_expn_arg(uint8_t *arg)
{ CURR_EXPANSION.argv[CURR_EXPANSION.argc++] = strdup(arg); }
INLINE void eval_expn(void)
{
uint8_t *macro = upsert(CURR_EXPANSION.id);
yymacroeval(macro);
}
INLINE void print_expn_id(void)
{ fputs(CURR_EXPANSION.id, OUTPUT); }
INLINE void join_argv(void)
{
if (CURR_EXPANSION.argv_joined) return;
uint8_t *argvcpy = CURR_EXPANSION.argv, *arg;
while ((*arg = *argvcpy++))
strncat(CURR_EXPANSION.argv_joined, arg, strlen(arg));
}
INLINE void join_argv_delim(void)
{
if (CURR_EXPANSION.argv_joined_delim) return;
uint8_t *argvcpy = CURR_EXPANSION.argv, *arg;
while ((*arg = *argvcpy++))
{
strncat(argv_joined, arg, strlen(arg));
strncat(
CURR_EXPANSION.argv_joined_delim,
LEX_STATE.expansiondelim,
MAX_TOKEN_LEN);
}
}
INLINE void set_environ(uint8_t *key, uint8_t *val)
{ setenv(key, val, false); }
LOCAL yyreflect(uint8_t *code);
LOCAL yyordinaryeval(void);
LOCAL void exit_action(void)
{
dump_symtbl(); close_file();
free_expn(); free_ident_re();
close_file(); dump_stack();
free_invoke_args(); set_delim_exec(NULL);
}
void signal_end(int signum)
{ if (signum == SIGINT) exit_action(); }
#define YY_ENGAGE_EXPR 1
#define YY_ENGAGE_MACRO 2
#define YY_ENGAGE_ORD 3
#define YY_ENGAGE_REFLECT 4
#define YY_ENGAGE_PREFLECT 5
LOCAL int yyengage = YY_ENGAGE_ORD;
LOCAL char **CMDL_ARGV;
LOCAL int CMDL_ARGC;
INLINE print_argv_idx(int idx)
{ if (idx < CMDL_ARGC) fputs(CMDL_ARGV[idx], OUTPUT); }
INLINE print_environ_name(uint8_t *name)
{ fputs(getenv(name), OUTPUT); }
LOCAL repl(void)
{ char *l = readline(NULL); yyreflect(l); free(l); }
LOCAL yyparamreflect(uint8_t *code, uint8_t *param)
LOCAL void reflect_foreach(uint8_t *code)
{
for (uint8_t *iarg = *INVOKE_ARGS; iarg; iarg = *(++INVOKE_ARGS))
{
yyparamreflect(code, iarg);
}
}
extern char *optarg;
LOCAL FILE *INPUT_STREAM;
LOCAL uint8_t *INPUT_PATH;
LOCAL uint8_t *OUTPUT_PATH;
LOCAL uint8_t *YY_PARAM;
LOCAL void parse_cmdl_args(void)
{
}
LOCAL void initialize(void)
{
signal(SIGINT, signal_end);
atexit(exit_action);
}
%}
%union {
uint8_t *string;
int64_t integer;
double floatnum;
}
%token MACRO_FINISHER
%token MACRO_ARGNUMPREFIX
%token MACRO_ARGEXPANSION
%token MACRO_DELIMEXPANSION
%token MACRO_EXPANSIONDELIM
%token MACRO_NAME
%token COMMENT_START
%token COMMENT_END
%token QUOTE_START
%token QUOTE_END
%token ESCAPE_MARK
%token DEFINE_MARK
%token UNDEFINE_MARK
%token PUSH_MARK
%token POP_MARK
%token EVAL_MARK
%token EXEC_MARK
%token ECHO_MARK
%token MODE_MARK
%token DIVERT_MARK
%token AUX_MARK
%token IF_MARK
%token ELSE_MARK
%token PARAM_MARK
%token REFLECT_MARK
%token REPEAT_MARK
%token DELIM_BEGIN
%token DELIM_END
%token PARSE_DELIM
%token IDENT
%token STRING
%token YY_PARAM
%token DEC_INT
%token HEX_INT
%token OCT_INT
%token BIN_INT
%token FLOAT
%token SHIFT_LEFT
%token SHIFT_RIGHT
%token DIV_INT
%token INCR
%token DECR
%token POW
%token INTO
%token DUMP
%token DEFINED
%token UNDEFINED
%token MATCHES
%token EQUALS
%token UNEQUALS
%token SWITCH
%token PUSH
%token POP
%token INDEX
%token TRANSLIT
%token DATEFMT
%token DELIMCMD
%token SET
%token GETLINE
%token ENVIRON
%token DIVERT_PREFIX
%token DIVERT_NUM
%token DIVERT_NULL
%token LNDELIM
%token YYEND_EXPR YYEND_MACRO YYEND_REFLECT YYEND_PREFLECT YYEND_ORD
%left '+' '-'
%left '/' '*' DIV_INT POW
%left '%'
%right '^'
%right '&'
%right '|'
%%
%%
void yyreflect(uint8_t *code)
{
INPUT_STREAM = fmemopen(code, strlen(code), "r");
yyengage = YY_ENGAGE_REFLECT;
yyparse();
}
void yyparamreflect(uint8_t *code, uint8_t *param)
{
INPUT_STREAM = fmemopen(code, strlen(code), "r");
YY_PARAM = param;
yyengage = YY_ENGAGE_PREFLECT;
yyparse();
}
void yyexpreval(uint8_t *code)
{
INPUT_STREAM = fmemopen(code, strlen(code), "r");
yyengage = YY_ENGAGE_EXPR;
yyparse();
}
void yymacroeval(uint8_t *code)
{
INPUT_STREAM = fmemopen(code, strlen(code), "r");
yyengage = YY_ENGAGE_MACRO;
yyparse();
}
void yyordinaryeval(void)
{
INPUT_STREAM = fmemopen(INPUT_PATH, "w");
yyengage = YY_ENGAGE_ORD;
yyparse();
}
/*!re2c
re2c:define:YYCTYPE = uint8_t;
re2c:yyfill:enable = 0;
*/
int yylex(void)
{
uint8_t token[MAX_LINE];
size_t len;
if (getdelim(&token, &len, LEX_STATE.parse_delim, INPUT_STREAM) < 0)
{
if (yyengage == YY_ENGAGE_EXPR)
return YYEND_EXPR;
else if (yyengage == YY_ENGAGE_MACRO)
return YYEND_MACRO;
else if (yyengage == YY_ENGAGE_PREFLECT)
return YYEND_PREFLECT;
else if (yyengage == YY_ENGAGE_REFLECT)
return YYEND_REFLECT;
else if (yyengage == YY_ENGAGE_ORD)
return YYEND_ORD;
}
uint8_t *YYCURSOR = token;
if (yyengage == YY_ENGAGE_EXPR)
{
/*!re2c
[+-][1-9][0-9]* { return DEC_INT; }
[0xX][a-fA-F0-9]+ { return HEX_INT; }
[0oO][0-7]+ { return OCT_INT; }
[0bB][0-1]+ { return BIN_INT; }
[+-][0-9]*[.eE][0-9]+ { return FLOAT; }
"<<" { return SHIFT_LEFT; }
">>" { return SHIFT_RIGHT; }
"//" { return INT_DIV; }
"++" { return INCR; }
"--" { return DECR; }
"**" { return POW; }
*/
}
else if (yyengage == YY_ENGAGE_PREFLECT)
{
if (!strncmp(token, LEX_STATE.param_mark, MAX_TOKEN_LEN))
return REFLECT_PARAM;
}
else if (yyengage == YY_ENGAGE_MACRO)
{
if (!strncmp(token, LEX_STATE.macro_argnumprefix, MAX_TOKEN_LEN))
return MACRO_ARGNUMPREFIX;
if (!strncmp(token, LEX_STATE.macro_argexpansion, MAX_TOKEN_LEN))
return MACRO_ARGEXPANSION;
if (!strncmp(token, LEX_STATE.macro_delimexpansion, MAX_TOKLEN_LEN))
return MACRO_DELIMEXPANSION;
if (!strncmp(token, LEX_STATE.macro_name, MAX_TOKEN_LEN))
return MACRO_NAME;
}
if (!strncmp(token, LEX_STATE.macro_prefix, MAX_TOKEN_LEN))
return MACRO_PREFIX;
if (!strncmp(token, LEX_STATE.macro_suffix, MAX_TOKEN_LEN))
return MACRO_SUFFIX;
if (!strncmp(token, LEX_STATE.macro_leftbrack, MAX_TOKEN_LEN))
return MACRO_LEFTBRACK;
if (!strncmp(token, LEX_STATE.macro_rightbrack, MAX_TOKEN_LEN))
return MACRO_RIGHTBRACK;
if (!strncmp(token, LEX_STATE.macro_separator, MAX_TOKEN_LEN))
return MACRO_SEPARATOR;
if (!strncmp(token, LEX_STATE.macro_finisher, MAX_TOKEN_LEN))
return MACRO_FINISHER;
if (!strncmp(token, LEX_STATE.macro_name, MAX_TOKEN_LEN))
return MACRO_NAME;
if (!strncmp(token, LEX_STATE.comment_start, MAX_TOKEN_LEN))
return COMMENT_START;
if (!strncmp(token, LEX_STATE.comment_end, MAX_TOKEN_LEN))
return COMMENT_END;
if (!strncmp(token, LEX_STATE.quote_start, MAX_TOKEN_LEN))
return QUOTE_START;
if (!strncmp(token, LEX_STATE.quote_end, MAX_TOKEN_LEN))
return QUOTE_END;
if (!strncmp(token, LEX_STATE.escape_mark, MAX_TOKEN_LEN))
return ESCAPE_MARK;
if (!strncmp(token, LEX_STATE.define_mark, MAX_TOKEN_LEN))
return DEFINE_MARK;
if (!strncmp(token, LEX_STATE.undefine_mark, MAX_TOKEN_LEN))
return UNDEFINE_MARK;
if (!strncmp(token, LEX_STATE.push_mark, MAX_TOKEN_LEN))
return PUSH_MARK;
if (!strncmp(token, LEX_STATE.pop_mark, MAX_TOKEN_LEN))
return POP_MARK;
if (!strncmp(token, LEX_STATE.eval_mark, MAX_TOKEN_LEN))
return EVAL_MARK;
if (!strncmp(token, LEX_STATE.exec_mark, MAX_TOKEN_LEN))
return EXEC_MARK;
if (!strncmp(token, LEX_STATE.echo_mark, MAX_TOKEN_LEN))
return ECHO_MARK;
if (!strncmp(token, LEX_STATE.mode_mark, MAX_TOKEN_LEN))
return MODE_MARK;
if (!strncmp(token, LEX_STATE.divert_mark, MAX_TOKEN_LEN))
return DIVERT_MARK;
if (!strncmp(token, LEX_STATE.aux_mark, MAX_TOKEN_LEN))
return AUX_MARK;
if (!strncmp(token, LEX_STATE.if_mark, MAX_TOKEN_LEN))
return IF_MARK;
if (!strncmp(token, LEX_STATE.else_mark, MAX_TOKEN_LEN))
return ELSE_MARK;
if (!strncmp(token, LEX_STATE.reflect_mark, MAX_TOKEN_LEN))
return REFLECT_MARK;
if (!strncmp(token, LEX_STATE.repeat_mark, MAX_TOKEN_LEN))
return REPEAT_MARK;
if (!strncmp(token, LEX_STATE.delim_begin, MAX_TOKEN_LEN))
return DELIM_BEGIN;
if (!strncmp(token, LEX_STATE.delim_end, MAX_TOKEN_LEN))
return DELIM_END;
if (!strncmp(token, YY_PARAM, len))
return YY_PARAM;
if (match_ident(token))
return IDENT;
if (match_string(token))
return STRING;
/*!re2c
"into" { return INTO; }
"dump" { return DUMP; }
"defined" { return DEFINED; }
"undefined" { return UNDIEFNED; }
"equals" { return EQUALS; }
"unequals" { return UNEQUALS; }
"matches" { return MATCHES; }
"unmatches" { return UNMAtCHES; }
"translit" { return TRANSLIT; }
"index" { return INDEX; }
"switch" { return SWITCH; }
"push" { return PUSH; }
"pop" { return POP; }
"set" { return SET; }
"datefmt" { return DATEFMT; }
"delimcmd" { return DELIMCMD; }
"environ" { return ENVIRON; }
"getline" { return GETLINE; }
"lndelim" { return LNDELIM; }
"DIVERT::" { return DIVERT_PREFIX; }
'[' [0-9] ']' { return DIVERT_NUM; }
"[NULL]" { return DIVERT_NULL; }
*/
fputs(token, OUTPUT);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment