Completely revamp expression engine.

This commit is contained in:
Dianne Skoll
2024-05-29 22:55:11 -04:00
parent 7728e09337
commit d2b43605ad
22 changed files with 2716 additions and 1654 deletions

View File

@@ -166,6 +166,10 @@
#define PASSTHRU_LEN 32 #define PASSTHRU_LEN 32
#define MAX_RECURSION_LEVEL 1000
#define MAX_FUNC_ARGS 64
#define PSBEGIN "# rem2ps begin" #define PSBEGIN "# rem2ps begin"
#define PSEND "# rem2ps end" #define PSEND "# rem2ps end"

View File

@@ -166,6 +166,10 @@
#define PASSTHRU_LEN 32 #define PASSTHRU_LEN 32
#define MAX_RECURSION_LEVEL 1000
#define MAX_FUNC_ARGS 64
#define PSBEGIN "# rem2ps begin" #define PSBEGIN "# rem2ps begin"
#define PSEND "# rem2ps end" #define PSEND "# rem2ps end"

View File

@@ -1268,20 +1268,28 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
{ {
int iter, dse, r, start; int iter, dse, r, start;
Value v; Value v;
char const *s; expr_node *sat_node;
char const *t; int nonconst = 0;
t = p->pos; sat_node = ParseExpr(p, &r);
if (r != OK) {
return r;
}
if (!sat_node) {
return E_SWERR;
}
iter = 0; iter = 0;
start = trig->scanfrom; start = trig->scanfrom;
while (iter++ < MaxSatIter) { while (iter++ < MaxSatIter) {
dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, 0); dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, 0);
if (r) { if (r) {
free_expr_tree(sat_node);
if (r == E_CANT_TRIG) return OK; else return r; if (r == E_CANT_TRIG) return OK; else return r;
} }
if (dse != start && trig->duration_days) { if (dse != start && trig->duration_days) {
dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, trig->duration_days); dse = ComputeTriggerNoAdjustDuration(start, trig, tt, &r, 1, trig->duration_days);
if (r) { if (r) {
free_expr_tree(sat_node);
if (r == E_CANT_TRIG) return OK; else return r; if (r == E_CANT_TRIG) return OK; else return r;
} }
} else if (dse == start) { } else if (dse == start) {
@@ -1294,13 +1302,18 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
SaveAllTriggerInfo(trig, tt, dse, tt->ttime, 1); SaveAllTriggerInfo(trig, tt, dse, tt->ttime, 1);
} }
if (dse == -1) { if (dse == -1) {
free_expr_tree(sat_node);
return E_EXPIRED; return E_EXPIRED;
} }
s = p->pos; r = evaluate_expr_node(sat_node, NULL, &v, &nonconst);
r = EvaluateExpr(p, &v); if (r) {
t = p->pos; free_expr_tree(sat_node);
if (r) return r; return r;
if (v.type != INT_TYPE && v.type != STR_TYPE) return E_BAD_TYPE; }
if (v.type != INT_TYPE && v.type != STR_TYPE) {
free_expr_tree(sat_node);
return E_BAD_TYPE;
}
if ((v.type == INT_TYPE && v.v.val) || if ((v.type == INT_TYPE && v.v.val) ||
(v.type == STR_TYPE && *v.v.str)) { (v.type == STR_TYPE && *v.v.str)) {
AdjustTriggerForDuration(trig->scanfrom, dse, trig, tt, 1); AdjustTriggerForDuration(trig->scanfrom, dse, trig, tt, 1);
@@ -1325,17 +1338,17 @@ int DoSatRemind(Trigger *trig, TimeTrig *tt, ParsePtr p)
} }
fprintf(ErrFp, "\n"); fprintf(ErrFp, "\n");
} }
free_expr_tree(sat_node);
return OK; return OK;
} }
p->pos = s;
if (dse+trig->duration_days < start) { if (dse+trig->duration_days < start) {
start++; start++;
} else { } else {
start = dse+trig->duration_days+1; start = dse+trig->duration_days+1;
} }
} }
p->pos = t;
LastTrigValid = 0; LastTrigValid = 0;
free_expr_tree(sat_node);
return E_CANT_TRIG; return E_CANT_TRIG;
} }

View File

@@ -12,6 +12,7 @@
/***************************************************************/ /***************************************************************/
#include "config.h" #include "config.h"
#include "types.h"
#include "expr.h" #include "expr.h"
#define L_IN_DOSUBST #define L_IN_DOSUBST
#include <stdio.h> #include <stdio.h>
@@ -20,7 +21,6 @@
#include <stdlib.h> #include <stdlib.h>
#include "types.h"
#include "globals.h" #include "globals.h"
#include "err.h" #include "err.h"
#include "protos.h" #include "protos.h"

View File

@@ -124,7 +124,9 @@ int DBufPuts(DynamicBuffer *dbuf, char const *str)
**********************************************************************/ **********************************************************************/
void DBufFree(DynamicBuffer *dbuf) void DBufFree(DynamicBuffer *dbuf)
{ {
if (dbuf->buffer != dbuf->staticBuf) free(dbuf->buffer); if (dbuf->buffer != NULL && dbuf->buffer != dbuf->staticBuf) {
free(dbuf->buffer);
}
DBufInit(dbuf); DBufInit(dbuf);
} }

View File

@@ -184,7 +184,7 @@ EXTERN char *ErrMsg[]
"RUN disabled", "RUN disabled",
"Domain error", "Domain error",
"Invalid identifier", "Invalid identifier",
"Recursive function call detected", "Too many recursive function calls",
"", "",
"Cannot modify system variable", "Cannot modify system variable",
"C library function can't represent date/time", "C library function can't represent date/time",

3140
src/expr.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,15 +1,19 @@
/***************************************************************/ /***************************************************************/
/* */ /* */
/* EXPR.H */ /* EXPR_NEW.H */
/* */ /* */
/* Contains a few definitions used by expression evaluator. */ /* Contains a few definitions used by expression pareser and */
/* evaluator. */
/* */ /* */
/* This file is part of REMIND. */ /* This file is part of REMIND. */
/* Copyright (C) 1992-2024 by Dianne Skoll */ /* Copyright (C) 2022 by Dianne Skoll */
/* SPDX-License-Identifier: GPL-2.0-only */
/* */ /* */
/***************************************************************/ /***************************************************************/
typedef struct udf_struct UserFunc;
expr_node *parse_expression(char const **e, int *r, Var *locals);
/* Define the types of values */ /* Define the types of values */
#define ERR_TYPE 0 #define ERR_TYPE 0
#define INT_TYPE 1 #define INT_TYPE 1
@@ -20,43 +24,10 @@
#define SPECIAL_TYPE 6 /* Only for system variables */ #define SPECIAL_TYPE 6 /* Only for system variables */
#define CONST_INT_TYPE 7 /* Only for system variables */ #define CONST_INT_TYPE 7 /* Only for system variables */
/* Define stuff for parsing expressions */
#define BEG_OF_EXPR '[' #define BEG_OF_EXPR '['
#define END_OF_EXPR ']' #define END_OF_EXPR ']'
#define COMMA ',' #define COMMA ','
#define UN_OP 0 /* Unary operator */
#define BIN_OP 1 /* Binary Operator */
#define FUNC 2 /* Function */
/* Make the pushing and popping of values and operators in-line code
for speed. BEWARE: These macros invoke return if an error happens ! */
#define PushOpStack(op) \
do { if (OpStackPtr >= OP_STACK_SIZE) return E_OP_STK_OVER; \
else { OpStack[OpStackPtr++] = (op); if (OpStackPtr > OpStackHiWater) OpStackHiWater = OpStackPtr; } } while(0)
#define PopOpStack(op) \
if (OpStackPtr <= 0) \
return E_OP_STK_UNDER; \
else \
(op) = OpStack[--OpStackPtr]
#define PushValStack(val) \
do { if (ValStackPtr >= VAL_STACK_SIZE) { \
DestroyValue(val); \
return E_VA_STK_OVER; \
} else { \
ValStack[ValStackPtr++] = (val); \
if (ValStackPtr > ValStackHiWater) ValStackHiWater = ValStackPtr; \
} } while (0);
#define PopValStack(val) \
if (ValStackPtr <= 0) \
return E_VA_STK_UNDER; \
else \
(val) = ValStack[--ValStackPtr]
/* These functions are in utils.c and are used to detect overflow /* These functions are in utils.c and are used to detect overflow
in various arithmetic operators. They have to be in separate in various arithmetic operators. They have to be in separate
functions with extern linkage to defeat compiler optimizations functions with extern linkage to defeat compiler optimizations
@@ -64,4 +35,3 @@ else \
extern int _private_mul_overflow(int a, int b); extern int _private_mul_overflow(int a, int b);
extern int _private_add_overflow(int a, int b); extern int _private_add_overflow(int a, int b);
extern int _private_sub_overflow(int a, int b); extern int _private_sub_overflow(int a, int b);

View File

@@ -60,6 +60,8 @@
#define Nargs (info->nargs) #define Nargs (info->nargs)
#define RetVal (info->retval) #define RetVal (info->retval)
#define DBG(x) do { if (DebugFlag & DB_PRTEXPR) { x; } } while(0)
static int static int
solstice_equinox_for_year(int y, int which); solstice_equinox_for_year(int y, int which);
@@ -74,7 +76,7 @@ static int FArgs (func_info *);
static int FAsc (func_info *); static int FAsc (func_info *);
static int FBaseyr (func_info *); static int FBaseyr (func_info *);
static int FChar (func_info *); static int FChar (func_info *);
static int FChoose (func_info *); static int FChoose (expr_node *, Value *, Value *, int *);
static int FCoerce (func_info *); static int FCoerce (func_info *);
static int FColumns (func_info *); static int FColumns (func_info *);
static int FCurrent (func_info *); static int FCurrent (func_info *);
@@ -101,7 +103,7 @@ static int FHebyear (func_info *);
static int FHour (func_info *); static int FHour (func_info *);
static int FHtmlEscape (func_info *); static int FHtmlEscape (func_info *);
static int FHtmlStriptags (func_info *); static int FHtmlStriptags (func_info *);
static int FIif (func_info *); static int FIif (expr_node *, Value *, Value *, int *);
static int FIndex (func_info *); static int FIndex (func_info *);
static int FIsAny (func_info *); static int FIsAny (func_info *);
static int FIsdst (func_info *); static int FIsdst (func_info *);
@@ -180,14 +182,9 @@ static int FWkday (func_info *);
static int FWkdaynum (func_info *); static int FWkdaynum (func_info *);
static int FYear (func_info *); static int FYear (func_info *);
static int CleanUpAfterFunc (func_info *);
static int CheckArgs (BuiltinFunc *f, int nargs);
static int SunStuff (int rise, double cosz, int dse); static int SunStuff (int rise, double cosz, int dse);
static int tz_set_tz (char const *tz); static int tz_set_tz (char const *tz);
/* "Overload" the struct Operator definition */
#define NO_MAX 127
/* Caches for extracting months, days, years from dates - may /* Caches for extracting months, days, years from dates - may
improve performance slightly. */ improve performance slightly. */
static int CacheDse = -1; static int CacheDse = -1;
@@ -196,14 +193,9 @@ static int CacheYear, CacheMon, CacheDay;
static int CacheHebDse = -1; static int CacheHebDse = -1;
static int CacheHebYear, CacheHebMon, CacheHebDay; static int CacheHebYear, CacheHebMon, CacheHebDay;
/* We need access to the value stack */
extern Value ValStack[];
extern int ValStackPtr;
extern int ValStackHiWater;
/* Macro for accessing arguments from the value stack - args are numbered /* Macro for accessing arguments from the value stack - args are numbered
from 0 to (Nargs - 1) */ from 0 to (Nargs - 1) */
#define ARG(x) (ValStack[ValStackPtr - Nargs + (x)]) #define ARG(x) (info->args[x])
#define ARGV(x) ARG(x).v.val #define ARGV(x) ARG(x).v.val
#define ARGSTR(x) ARG(x).v.str #define ARGSTR(x) ARG(x).v.str
@@ -231,215 +223,127 @@ extern int ValStackHiWater;
/* The array holding the built-in functions. */ /* The array holding the built-in functions. */
BuiltinFunc Func[] = { BuiltinFunc Func[] = {
/* Name minargs maxargs is_constant func */ /* Name minargs maxargs is_constant func newfunc*/
{ "abs", 1, 1, 1, FAbs }, { "abs", 1, 1, 1, FAbs, NULL },
{ "access", 2, 2, 0, FAccess }, { "access", 2, 2, 0, FAccess, NULL },
{ "adawn", 0, 1, 0, FADawn}, { "adawn", 0, 1, 0, FADawn, NULL},
{ "adusk", 0, 1, 0, FADusk}, { "adusk", 0, 1, 0, FADusk, NULL},
{ "ampm", 1, 3, 1, FAmpm }, { "ampm", 1, 3, 1, FAmpm, NULL },
{ "ansicolor", 1, 5, 1, FAnsicolor }, { "ansicolor", 1, 5, 1, FAnsicolor, NULL },
{ "args", 1, 1, 0, FArgs }, { "args", 1, 1, 0, FArgs, NULL },
{ "asc", 1, 1, 1, FAsc }, { "asc", 1, 1, 1, FAsc, NULL },
{ "baseyr", 0, 0, 1, FBaseyr }, { "baseyr", 0, 0, 1, FBaseyr, NULL },
{ "char", 1, NO_MAX, 1, FChar }, { "char", 1, NO_MAX, 1, FChar, NULL },
{ "choose", 2, NO_MAX, 1, FChoose }, { "choose", 2, NO_MAX, 1, NULL, FChoose }, /*NEW-STYLE*/
{ "coerce", 2, 2, 1, FCoerce }, { "coerce", 2, 2, 1, FCoerce, NULL },
{ "columns", 0, 1, 0, FColumns }, { "columns", 0, 1, 0, FColumns, NULL },
{ "current", 0, 0, 0, FCurrent }, { "current", 0, 0, 0, FCurrent, NULL },
{ "date", 3, 3, 1, FDate }, { "date", 3, 3, 1, FDate, NULL },
{ "datepart", 1, 1, 1, FDatepart }, { "datepart", 1, 1, 1, FDatepart, NULL },
{ "datetime", 2, 5, 1, FDateTime }, { "datetime", 2, 5, 1, FDateTime, NULL },
{ "dawn", 0, 1, 0, FDawn}, { "dawn", 0, 1, 0, FDawn, NULL },
{ "day", 1, 1, 1, FDay }, { "day", 1, 1, 1, FDay, NULL },
{ "daysinmon", 2, 2, 1, FDaysinmon }, { "daysinmon", 2, 2, 1, FDaysinmon, NULL },
{ "defined", 1, 1, 0, FDefined }, { "defined", 1, 1, 0, FDefined, NULL },
{ "dosubst", 1, 3, 0, FDosubst }, { "dosubst", 1, 3, 0, FDosubst, NULL },
{ "dusk", 0, 1, 0, FDusk }, { "dusk", 0, 1, 0, FDusk, NULL },
{ "easterdate", 0, 1, 0, FEasterdate }, { "easterdate", 0, 1, 0, FEasterdate, NULL },
{ "evaltrig", 1, 2, 0, FEvalTrig }, { "evaltrig", 1, 2, 0, FEvalTrig, NULL },
{ "filedate", 1, 1, 0, FFiledate }, { "filedate", 1, 1, 0, FFiledate, NULL },
{ "filedatetime", 1, 1, 0, FFiledatetime }, { "filedatetime", 1, 1, 0, FFiledatetime, NULL },
{ "filedir", 0, 0, 0, FFiledir }, { "filedir", 0, 0, 0, FFiledir, NULL },
{ "filename", 0, 0, 0, FFilename }, { "filename", 0, 0, 0, FFilename, NULL },
{ "getenv", 1, 1, 0, FGetenv }, { "getenv", 1, 1, 0, FGetenv, NULL },
{ "hebdate", 2, 5, 0, FHebdate }, { "hebdate", 2, 5, 0, FHebdate, NULL },
{ "hebday", 1, 1, 0, FHebday }, { "hebday", 1, 1, 0, FHebday, NULL },
{ "hebmon", 1, 1, 0, FHebmon }, { "hebmon", 1, 1, 0, FHebmon, NULL },
{ "hebyear", 1, 1, 0, FHebyear }, { "hebyear", 1, 1, 0, FHebyear, NULL },
{ "hour", 1, 1, 1, FHour }, { "hour", 1, 1, 1, FHour, NULL },
{ "htmlescape", 1, 1, 1, FHtmlEscape }, { "htmlescape", 1, 1, 1, FHtmlEscape, NULL },
{ "htmlstriptags",1, 1, 1, FHtmlStriptags }, { "htmlstriptags",1, 1, 1, FHtmlStriptags, NULL },
{ "iif", 1, NO_MAX, 1, FIif }, { "iif", 1, NO_MAX, 1, NULL, FIif }, /*NEW-STYLE*/
{ "index", 2, 3, 1, FIndex }, { "index", 2, 3, 1, FIndex, NULL },
{ "isany", 1, NO_MAX, 1, FIsAny }, { "isany", 1, NO_MAX, 1, FIsAny, NULL },
{ "isdst", 0, 2, 0, FIsdst }, { "isdst", 0, 2, 0, FIsdst, NULL },
{ "isleap", 1, 1, 1, FIsleap }, { "isleap", 1, 1, 1, FIsleap, NULL },
{ "isomitted", 1, 1, 0, FIsomitted }, { "isomitted", 1, 1, 0, FIsomitted, NULL },
{ "language", 0, 0, 1, FLanguage }, { "language", 0, 0, 1, FLanguage, NULL },
{ "localtoutc", 1, 1, 1, FLocalToUTC }, { "localtoutc", 1, 1, 1, FLocalToUTC, NULL },
{ "lower", 1, 1, 1, FLower }, { "lower", 1, 1, 1, FLower, NULL },
{ "max", 1, NO_MAX, 1, FMax }, { "max", 1, NO_MAX, 1, FMax, NULL },
{ "min", 1, NO_MAX, 1, FMin }, { "min", 1, NO_MAX, 1, FMin, NULL },
{ "minsfromutc", 0, 2, 0, FMinsfromutc }, { "minsfromutc", 0, 2, 0, FMinsfromutc, NULL },
{ "minute", 1, 1, 1, FMinute }, { "minute", 1, 1, 1, FMinute, NULL },
{ "mon", 1, 1, 1, FMon }, { "mon", 1, 1, 1, FMon, NULL },
{ "monnum", 1, 1, 1, FMonnum }, { "monnum", 1, 1, 1, FMonnum, NULL },
{ "moondate", 1, 3, 0, FMoondate }, { "moondate", 1, 3, 0, FMoondate, NULL },
{ "moondatetime", 1, 3, 0, FMoondatetime }, { "moondatetime", 1, 3, 0, FMoondatetime, NULL },
{ "moonphase", 0, 2, 0, FMoonphase }, { "moonphase", 0, 2, 0, FMoonphase, NULL },
{ "moontime", 1, 3, 0, FMoontime }, { "moontime", 1, 3, 0, FMoontime, NULL },
{ "multitrig", 1, NO_MAX, 0, FMultiTrig }, { "multitrig", 1, NO_MAX, 0, FMultiTrig, NULL },
{ "ndawn", 0, 1, 0, FNDawn}, { "ndawn", 0, 1, 0, FNDawn, NULL },
{ "ndusk", 0, 1, 0, FNDusk}, { "ndusk", 0, 1, 0, FNDusk, NULL },
{ "nonomitted", 2, NO_MAX, 0, FNonomitted }, { "nonomitted", 2, NO_MAX, 0, FNonomitted, NULL },
{ "now", 0, 0, 0, FNow }, { "now", 0, 0, 0, FNow, NULL },
{ "ord", 1, 1, 1, FOrd }, { "ord", 1, 1, 1, FOrd, NULL },
{ "orthodoxeaster",0, 1, 0, FOrthodoxeaster }, { "orthodoxeaster",0, 1, 0, FOrthodoxeaster, NULL },
{ "ostype", 0, 0, 1, FOstype }, { "ostype", 0, 0, 1, FOstype, NULL },
{ "pad", 3, 4, 1, FPad }, { "pad", 3, 4, 1, FPad, NULL },
{ "plural", 1, 3, 1, FPlural }, { "plural", 1, 3, 1, FPlural, NULL },
{ "psmoon", 1, 4, 1, FPsmoon}, { "psmoon", 1, 4, 1, FPsmoon, NULL },
{ "psshade", 1, 3, 1, FPsshade}, { "psshade", 1, 3, 1, FPsshade, NULL },
{ "realcurrent", 0, 0, 0, FRealCurrent}, { "realcurrent", 0, 0, 0, FRealCurrent, NULL },
{ "realnow", 0, 0, 0, FRealnow}, { "realnow", 0, 0, 0, FRealnow, NULL },
{ "realtoday", 0, 0, 0, FRealtoday }, { "realtoday", 0, 0, 0, FRealtoday, NULL },
{ "rows", 0, 0, 0, FRows }, { "rows", 0, 0, 0, FRows, NULL },
{ "sgn", 1, 1, 1, FSgn }, { "sgn", 1, 1, 1, FSgn, NULL },
{ "shell", 1, 2, 0, FShell }, { "shell", 1, 2, 0, FShell, NULL },
{ "shellescape", 1, 1, 1, FShellescape }, { "shellescape", 1, 1, 1, FShellescape, NULL },
{ "slide", 2, NO_MAX, 0, FSlide }, { "slide", 2, NO_MAX, 0, FSlide, NULL },
{ "soleq", 1, 2, 0, FSoleq }, { "soleq", 1, 2, 0, FSoleq, NULL },
{ "stdout", 0, 0, 1, FStdout }, { "stdout", 0, 0, 1, FStdout, NULL },
{ "strlen", 1, 1, 1, FStrlen }, { "strlen", 1, 1, 1, FStrlen, NULL },
{ "substr", 2, 3, 1, FSubstr }, { "substr", 2, 3, 1, FSubstr, NULL },
{ "sunrise", 0, 1, 0, FSunrise}, { "sunrise", 0, 1, 0, FSunrise, NULL },
{ "sunset", 0, 1, 0, FSunset }, { "sunset", 0, 1, 0, FSunset, NULL },
{ "time", 2, 2, 1, FTime }, { "time", 2, 2, 1, FTime, NULL },
{ "timepart", 1, 1, 1, FTimepart }, { "timepart", 1, 1, 1, FTimepart, NULL },
{ "timezone", 0, 1, 1, FTimezone }, { "timezone", 0, 1, 1, FTimezone, NULL },
{ "today", 0, 0, 0, FToday }, { "today", 0, 0, 0, FToday, NULL },
{ "trig", 0, NO_MAX, 0, FTrig }, { "trig", 0, NO_MAX, 0, FTrig, NULL },
{ "trigback", 0, 0, 0, FTrigback }, { "trigback", 0, 0, 0, FTrigback, NULL },
{ "trigdate", 0, 0, 0, FTrigdate }, { "trigdate", 0, 0, 0, FTrigdate, NULL },
{ "trigdatetime", 0, 0, 0, FTrigdatetime }, { "trigdatetime", 0, 0, 0, FTrigdatetime, NULL },
{ "trigdelta", 0, 0, 0, FTrigdelta }, { "trigdelta", 0, 0, 0, FTrigdelta, NULL },
{ "trigduration", 0, 0, 0, FTrigduration }, { "trigduration", 0, 0, 0, FTrigduration, NULL },
{ "trigeventduration", 0, 0, 0, FTrigeventduration }, { "trigeventduration", 0, 0, 0, FTrigeventduration, NULL },
{ "trigeventstart", 0, 0, 0, FTrigeventstart }, { "trigeventstart", 0, 0, 0, FTrigeventstart, NULL },
{ "trigfrom", 0, 0, 0, FTrigfrom }, { "trigfrom", 0, 0, 0, FTrigfrom, NULL },
{ "trigger", 1, 3, 0, FTrigger }, { "trigger", 1, 3, 0, FTrigger, NULL },
{ "trigpriority", 0, 0, 0, FTrigpriority }, { "trigpriority", 0, 0, 0, FTrigpriority, NULL },
{ "trigrep", 0, 0, 0, FTrigrep }, { "trigrep", 0, 0, 0, FTrigrep, NULL },
{ "trigscanfrom", 0, 0, 0, FTrigscanfrom }, { "trigscanfrom", 0, 0, 0, FTrigscanfrom, NULL },
{ "trigtags", 0, 0, 0, FTrigtags }, { "trigtags", 0, 0, 0, FTrigtags, NULL },
{ "trigtime", 0, 0, 0, FTrigtime }, { "trigtime", 0, 0, 0, FTrigtime, NULL },
{ "trigtimedelta",0, 0, 0, FTrigtimedelta }, { "trigtimedelta",0, 0, 0, FTrigtimedelta, NULL },
{ "trigtimerep", 0, 0, 0, FTrigtimerep }, { "trigtimerep", 0, 0, 0, FTrigtimerep, NULL },
{ "triguntil", 0, 0, 0, FTriguntil }, { "triguntil", 0, 0, 0, FTriguntil, NULL },
{ "trigvalid", 0, 0, 0, FTrigvalid }, { "trigvalid", 0, 0, 0, FTrigvalid, NULL },
{ "typeof", 1, 1, 1, FTypeof }, { "typeof", 1, 1, 1, FTypeof, NULL },
{ "tzconvert", 2, 3, 0, FTzconvert }, { "tzconvert", 2, 3, 0, FTzconvert, NULL },
{ "upper", 1, 1, 1, FUpper }, { "upper", 1, 1, 1, FUpper, NULL },
{ "utctolocal", 1, 1, 1, FUTCToLocal }, { "utctolocal", 1, 1, 1, FUTCToLocal, NULL },
{ "value", 1, 2, 0, FValue }, { "value", 1, 2, 0, FValue, NULL },
{ "version", 0, 0, 1, FVersion }, { "version", 0, 0, 1, FVersion, NULL },
{ "weekno", 0, 3, 1, FWeekno }, { "weekno", 0, 3, 1, FWeekno, NULL },
{ "wkday", 1, 1, 1, FWkday }, { "wkday", 1, 1, 1, FWkday, NULL },
{ "wkdaynum", 1, 1, 1, FWkdaynum }, { "wkdaynum", 1, 1, 1, FWkdaynum, NULL },
{ "year", 1, 1, 1, FYear } { "year", 1, 1, 1, FYear, NULL }
}; };
/* Need a variable here - Func[] array not really visible to outside. */ /* Need a variable here - Func[] array not really visible to outside. */
int NumFuncs = sizeof(Func) / sizeof(Operator) ; int NumFuncs = sizeof(Func) / sizeof(BuiltinFunc) ;
/***************************************************************/
/* */
/* CallFunc */
/* */
/* Call a function given a pointer to it, and the number */
/* of arguments supplied. */
/* */
/***************************************************************/
int CallFunc(BuiltinFunc *f, int nargs)
{
register int r = CheckArgs(f, nargs);
int i;
func_info info_obj;
func_info *info = &info_obj;
Nargs = nargs;
RetVal.type = ERR_TYPE;
if (DebugFlag & DB_PRTEXPR) {
fprintf(ErrFp, "%s(", f->name);
for (i=0; i<nargs; i++) {
PrintValue(&ARG(i), ErrFp);
if (i<nargs-1) fprintf(ErrFp, ", ");
}
fprintf(ErrFp, ") => ");
if (r) {
fprintf(ErrFp, "%s\n", ErrMsg[r]);
return r;
}
}
if (r) {
Eprint("%s(): %s", f->name, ErrMsg[r]);
return r;
}
r = (*(f->func))(info);
if (r) {
DestroyValue(RetVal);
if (DebugFlag & DB_PRTEXPR)
fprintf(ErrFp, "%s\n", ErrMsg[r]);
else
Eprint("%s(): %s", f->name, ErrMsg[r]);
return r;
}
if (DebugFlag & DB_PRTEXPR) {
PrintValue(&RetVal, ErrFp);
fprintf(ErrFp, "\n");
}
r = CleanUpAfterFunc(info);
return r;
}
/***************************************************************/
/* */
/* CheckArgs */
/* */
/* Check that the right number of args have been supplied */
/* for a function. */
/* */
/***************************************************************/
static int CheckArgs(BuiltinFunc *f, int nargs)
{
if (nargs < f->minargs) return E_2FEW_ARGS;
if (nargs > f->maxargs && f->maxargs != NO_MAX) return E_2MANY_ARGS;
return OK;
}
/***************************************************************/
/* */
/* CleanUpAfterFunc */
/* */
/* Clean up the stack after a function call - remove */
/* args and push the new value. */
/* */
/***************************************************************/
static int CleanUpAfterFunc(func_info *info)
{
Value v;
int i;
for (i=0; i<Nargs; i++) {
PopValStack(v);
DestroyValue(v);
}
PushValStack(RetVal);
return OK;
}
/***************************************************************/ /***************************************************************/
/* */ /* */
@@ -1279,6 +1183,9 @@ static int FIsAny(func_info *info)
return OK; return OK;
} }
/* Debugging helpers for "choose()" and "iif() */
#define PUT(x) DBufPuts(&DebugBuf, x)
#define OUT() do { fprintf(ErrFp, "%s\n", DBufValue(&DebugBuf)); DBufFree(&DebugBuf); } while(0)
/***************************************************************/ /***************************************************************/
/* */ /* */
/* FChoose */ /* FChoose */
@@ -1287,15 +1194,63 @@ static int FIsAny(func_info *info)
/* from 1. */ /* from 1. */
/* */ /* */
/***************************************************************/ /***************************************************************/
static int FChoose(func_info *info) static int FChoose(expr_node *node, Value *locals, Value *ans, int *nonconst)
{ {
int v; DynamicBuffer DebugBuf;
expr_node *cur;
int r;
int n;
int nargs = node->num_kids;
Value(v);
DBG(DBufInit(&DebugBuf));
PUT("choose(");
ASSERT_TYPE(0, INT_TYPE); cur = node->child;
v = ARGV(0); r = evaluate_expr_node(cur, locals, &v, nonconst);
if (v < 1) v = 1; if (r != OK) {
if (v > Nargs-1) v = Nargs-1; DBG(DBufFree(&DebugBuf));
DCOPYVAL(RetVal, ARG(v)); return r;
}
DBG(PUT(PrintValue(&v, NULL)));
if (v.type != INT_TYPE) {
if (DebugFlag & DB_PRTEXPR) {
cur = cur->sibling;
while(cur) {
PUT(", ?");
cur = cur->sibling;
}
PUT(") => ");
PUT(ErrMsg[E_BAD_TYPE]);
OUT();
}
return E_BAD_TYPE;
}
n = v.v.val;
if (n < 1) n = 1;
if (n > nargs-1) n = nargs-1;
while(n--) {
cur = cur->sibling;
DBG(if (n) { PUT(", ?"); });
if (!cur) return E_SWERR; /* Should not happen! */
}
r = evaluate_expr_node(cur, locals, ans, nonconst);
if (r != OK) {
DBG(DBufFree(&DebugBuf));
return r;
}
if (DebugFlag & DB_PRTEXPR) {
PUT(", ");
PUT(PrintValue(ans, NULL));
cur = cur->sibling;
while(cur) {
PUT(", ?");
cur = cur->sibling;
}
PUT(") => ");
PUT(PrintValue(ans, NULL));
OUT();
}
return OK; return OK;
} }
@@ -1481,7 +1436,7 @@ static int FValue(func_info *info)
ASSERT_TYPE(0, STR_TYPE); ASSERT_TYPE(0, STR_TYPE);
switch(Nargs) { switch(Nargs) {
case 1: case 1:
return GetVarValue(ARGSTR(0), &RetVal, NULL, NULL); return GetVarValue(ARGSTR(0), &RetVal);
case 2: case 2:
v = FindVar(ARGSTR(0), 0); v = FindVar(ARGSTR(0), 0);
@@ -1953,33 +1908,101 @@ static int FIndex(func_info *info)
/* */ /* */
/* FIif */ /* FIif */
/* */ /* */
/* The IIF function. */ /* The IIF function. Uses new-style evaluation */
/* */ /* */
/***************************************************************/ /***************************************************************/
static int FIif(func_info *info) static int FIif(expr_node *node, Value *locals, Value *ans, int *nonconst)
{ {
int istrue; int istrue;
int arg; int r;
int done;
Value v;
expr_node *cur;
DynamicBuffer DebugBuf;
if (!(Nargs % 2)) return E_IIF_ODD; DBG(DBufInit(&DebugBuf));
DBG(PUT("iif("));
cur = node->child;
for (arg=0; arg<Nargs-1; arg += 2) { if (!(node->num_kids % 2)) {
if (ARG(arg).type != STR_TYPE && ARG(arg).type != INT_TYPE) if (DebugFlag & DB_PRTEXPR) {
return E_BAD_TYPE; r = 0;
while(cur) {
if (ARG(arg).type == INT_TYPE) if (r) PUT(", ");
istrue = ARG(arg).v.val; r=1;
else PUT("?");
istrue = *(ARG(arg).v.str); cur = cur->sibling;
}
if (istrue) { PUT(") => ");
DCOPYVAL(RetVal, ARG(arg+1)); PUT(ErrMsg[E_IIF_ODD]);
return OK; OUT();
} }
return E_IIF_ODD;
} }
DCOPYVAL(RetVal, ARG(Nargs-1));
return OK; done = 0;
while(cur->sibling) {
r = evaluate_expr_node(cur, locals, &v, nonconst);
if (r != OK) {
DBG(DBufFree(&DebugBuf));
return r;
}
if (DebugFlag & DB_PRTEXPR) {
if (done) PUT(", ");
done = 1;
PUT(PrintValue(&v, NULL));
}
if (v.type != STR_TYPE && v.type != INT_TYPE) {
if (DebugFlag & DB_PRTEXPR) {
cur = cur->sibling;
while(cur) {
PUT(", ?");
cur = cur->sibling;
}
PUT(") => ");
PUT(ErrMsg[E_BAD_TYPE]);
OUT();
}
return E_BAD_TYPE;
}
if (v.type == INT_TYPE) {
istrue = v.v.val;
} else {
istrue = *(v.v.str);
}
if (istrue) {
r = evaluate_expr_node(cur->sibling, locals, ans, nonconst);
if (r == OK && (DebugFlag & DB_PRTEXPR)) {
PUT(", ");
PUT(PrintValue(ans, NULL));
cur = cur->sibling->sibling;
while(cur) {
PUT(", ?");
cur = cur->sibling;
}
PUT(") => ");
PUT(PrintValue(ans, NULL));
OUT();
}
DBG(DBufFree(&DebugBuf));
return r;
}
DBG(PUT(", ?"));
cur = cur->sibling->sibling;
}
/* Return the last arg */
r = evaluate_expr_node(cur, locals, ans, nonconst);
if (DebugFlag & DB_PRTEXPR) {
if (done) PUT(", ");
PUT(PrintValue(ans, NULL));
PUT(") => ");
PUT(PrintValue(ans, NULL));
OUT();
}
return r;
} }
/***************************************************************/ /***************************************************************/
@@ -2373,14 +2396,18 @@ static int FEasterdate(func_info *info)
{ {
int y, m, d; int y, m, d;
int g, c, x, z, e, n; int g, c, x, z, e, n;
int base;
if (Nargs == 0) { if (Nargs == 0) {
base = DSEToday;
FromDSE(DSEToday, &y, &m, &d); FromDSE(DSEToday, &y, &m, &d);
} else { } else {
if (ARG(0).type == INT_TYPE) { if (ARG(0).type == INT_TYPE) {
base = -1;
y = ARGV(0); y = ARGV(0);
if (y < BASE) return E_2LOW; if (y < BASE) return E_2LOW;
else if (y > BASE+YR_RANGE) return E_2HIGH; else if (y > BASE+YR_RANGE) return E_2HIGH;
} else if (HASDATE(ARG(0))) { } else if (HASDATE(ARG(0))) {
base = DATEPART(ARG(0));
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */ FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
} else return E_BAD_TYPE; } else return E_BAD_TYPE;
} }
@@ -2406,7 +2433,7 @@ static int FEasterdate(func_info *info)
RetVal.type = DATE_TYPE; RetVal.type = DATE_TYPE;
RETVAL = DSE(y, m, d); RETVAL = DSE(y, m, d);
y++; } while (HASDATE(ARG(0)) && RETVAL < DATEPART(ARG(0))); y++; } while (base > -1 && RETVAL < base);
return OK; return OK;
} }
@@ -2422,7 +2449,9 @@ static int FOrthodoxeaster(func_info *info)
{ {
int y, m, d; int y, m, d;
int a, b, c, dd, e, f, dse; int a, b, c, dd, e, f, dse;
int base = -1;
if (Nargs == 0) { if (Nargs == 0) {
base = DSEToday;
FromDSE(DSEToday, &y, &m, &d); FromDSE(DSEToday, &y, &m, &d);
} else { } else {
if (ARG(0).type == INT_TYPE) { if (ARG(0).type == INT_TYPE) {
@@ -2430,6 +2459,7 @@ static int FOrthodoxeaster(func_info *info)
if (y < BASE) return E_2LOW; if (y < BASE) return E_2LOW;
else if (y > BASE+YR_RANGE) return E_2HIGH; else if (y > BASE+YR_RANGE) return E_2HIGH;
} else if (HASDATE(ARG(0))) { } else if (HASDATE(ARG(0))) {
base = DATEPART(ARG(0));
FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */ FromDSE(DATEPART(ARG(0)), &y, &m, &d); /* We just want the year */
} else return E_BAD_TYPE; } else return E_BAD_TYPE;
} }
@@ -2449,7 +2479,7 @@ static int FOrthodoxeaster(func_info *info)
RetVal.type = DATE_TYPE; RetVal.type = DATE_TYPE;
RETVAL = dse; RETVAL = dse;
y++; y++;
} while (HASDATE(ARG(0)) && RETVAL < DATEPART(ARG(0))); } while (base > -1 && RETVAL < base);
return OK; return OK;
} }
@@ -3896,3 +3926,38 @@ FSoleq(func_info *info)
RETVAL = ret; RETVAL = ret;
return OK; return OK;
} }
/* Compare two strings case-insensitively, where we KNOW
that the second string is definitely lower-case */
static int strcmp_lcfirst(char const *s1, char const *s2)
{
int r;
while (*s1 && *s2) {
r = tolower(*s1) - *s2;
if (r) return r;
s1++;
s2++;
}
return tolower(*s1) - *s2;
}
/***************************************************************/
/* */
/* FindBuiltinFunc */
/* */
/* Find a built-in function. */
/* */
/***************************************************************/
BuiltinFunc *FindBuiltinFunc(char const *name)
{
int top=NumFuncs-1, bot=0;
int mid, r;
while (top >= bot) {
mid = (top + bot) / 2;
r = strcmp_lcfirst(name, Func[mid].name);
if (!r) return &Func[mid];
else if (r > 0) bot = mid+1;
else top = mid-1;
}
return NULL;
}

View File

@@ -159,6 +159,9 @@ EXTERN DynamicBuffer Banner;
EXTERN DynamicBuffer LineBuffer; EXTERN DynamicBuffer LineBuffer;
EXTERN DynamicBuffer ExprBuf; EXTERN DynamicBuffer ExprBuf;
/* User-func recursion level */
EXTERN INIT( unsigned int FuncRecursionLevel, 0);
extern int NumFullOmits, NumPartialOmits; extern int NumFullOmits, NumPartialOmits;
/* List of months */ /* List of months */

View File

@@ -605,7 +605,7 @@ void InitRemind(int argc, char const *argv[])
case 'D': case 'D':
while (*arg) { while (*arg) {
switch(*arg++) { switch(*arg++) {
case 's': case 'S': DebugFlag |= DB_EXPR_STACKS; break; case 's': case 'S': DebugFlag |= DB_PARSE_EXPR; break;
case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break; case 'e': case 'E': DebugFlag |= DB_ECHO_LINE; break;
case 'x': case 'X': DebugFlag |= DB_PRTEXPR; break; case 'x': case 'X': DebugFlag |= DB_PRTEXPR; break;
case 't': case 'T': DebugFlag |= DB_PRTTRIG; break; case 't': case 'T': DebugFlag |= DB_PRTTRIG; break;

View File

@@ -246,7 +246,9 @@ EXTERN char *ErrMsg[] =
"String too long", "String too long",
"Time specified twice", "Time specified twice",
"Cannot specify DURATION without specifying AT", "Cannot specify DURATION without specifying AT",
"Odotettu viikonpäivän nimi" "Odotettu viikonpäivän nimi",
"Päällekkäinen argumentin nimi"
}; };
#endif /* MK_GLOBALS */ #endif /* MK_GLOBALS */

View File

@@ -221,6 +221,7 @@ EXTERN char *ErrMsg[] =
"Time specified twice", "Time specified twice",
"Cannot specify DURATION without specifying AT", "Cannot specify DURATION without specifying AT",
"Nom du jour de la semaine attendu", "Nom du jour de la semaine attendu",
"Nom de l'argument en double",
}; };
#endif /* MK_GLOBALS */ #endif /* MK_GLOBALS */

View File

@@ -236,7 +236,8 @@ EXTERN char *ErrMsg[] =
"String too long", "String too long",
"Time specified twice", "Time specified twice",
"Cannot specify DURATION without specifying AT", "Cannot specify DURATION without specifying AT",
"Oczekiwana nazwa dnia tygodnia" "Oczekiwana nazwa dnia tygodnia",
"Zduplikowana nazwa argumentu",
}; };
#endif /* MK_GLOBALS */ #endif /* MK_GLOBALS */

View File

@@ -246,6 +246,7 @@ EXTERN char *ErrMsg[] =
"Time specified twice", "Time specified twice",
"Cannot specify DURATION without specifying AT", "Cannot specify DURATION without specifying AT",
"Esperando nome do dia da semana", "Esperando nome do dia da semana",
"Nome de argumento duplicado"
}; };
#endif /* MK_GLOBALS */ #endif /* MK_GLOBALS */

View File

@@ -55,6 +55,15 @@ static void DoReminders(void);
/* Macro for simplifying common block so as not to litter code */ /* Macro for simplifying common block so as not to litter code */
#define OUTPUT(c) do { if (output) { DBufPutc(output, c); } else { putchar(c); } } while(0) #define OUTPUT(c) do { if (output) { DBufPutc(output, c); } else { putchar(c); } } while(0)
void
exitfunc(void)
{
if (DebugFlag & DB_PARSE_EXPR) {
UnsetAllUserFuncs();
print_expr_nodes_stats();
}
}
/***************************************************************/ /***************************************************************/
/***************************************************************/ /***************************************************************/
/** **/ /** **/
@@ -81,7 +90,7 @@ int main(int argc, char *argv[])
DBufInit(&(LastTrigger.tags)); DBufInit(&(LastTrigger.tags));
ClearLastTriggers(); ClearLastTriggers();
atexit(DebugExitFunc); atexit(exitfunc);
if (DoCalendar || (DoSimpleCalendar && (!NextMode || PsCal))) { if (DoCalendar || (DoSimpleCalendar && (!NextMode || PsCal))) {
ProduceCalendar(); ProduceCalendar();
@@ -289,6 +298,7 @@ static void DoReminders(void)
case T_RemType: if (tok.val == RUN_TYPE) { case T_RemType: if (tok.val == RUN_TYPE) {
r=DoRun(&p); r=DoRun(&p);
} else { } else {
DestroyParser(&p);
CreateParser(CurLine, &p); CreateParser(CurLine, &p);
r=DoRem(&p); r=DoRem(&p);
purge_handled = 1; purge_handled = 1;
@@ -297,10 +307,8 @@ static void DoReminders(void)
/* If we don't recognize the command, do a REM by default */ /* If we don't recognize the command, do a REM by default */
/* Note: Since the parser hasn't been used yet, we don't */
/* need to destroy it here. */
default: CreateParser(CurLine, &p); purge_handled = 1; r=DoRem(&p); break; default: DestroyParser(&p); CreateParser(CurLine, &p); purge_handled = 1; r=DoRem(&p); break;
} }
if (r && (!Hush || r != E_RUN_DISABLED)) { if (r && (!Hush || r != E_RUN_DISABLED)) {
@@ -582,6 +590,53 @@ int ParseIdentifier(ParsePtr p, DynamicBuffer *dbuf)
} }
} }
/***************************************************************/
/* */
/* ParseExpr */
/* */
/* We are expecting an expression here. Parse it and return */
/* the value node tree. */
/* */
/***************************************************************/
expr_node * ParseExpr(ParsePtr p, int *r)
{
int bracketed = 0;
expr_node *node;
if (p->isnested) {
*r = E_PARSE_ERR; /* Can't nest expressions */
return NULL;
}
if (!p->pos) {
*r = E_PARSE_ERR; /* Missing expression */
return NULL;
}
while (isempty(*p->pos)) (p->pos)++;
if (!*(p->pos)) {
*r = E_EOLN;
return NULL;
}
if (*p->pos == BEG_OF_EXPR) {
(p->pos)++;
bracketed = 1;
}
node = parse_expression(&(p->pos), r, NULL);
if (*r) {
return free_expr_tree(node);
}
if (bracketed) {
if (*p->pos != END_OF_EXPR) {
*r = E_MISS_END;
return free_expr_tree(node);
}
(p->pos)++;
}
return node;
}
/***************************************************************/ /***************************************************************/
/* */ /* */
/* EvaluateExpr */ /* EvaluateExpr */
@@ -593,21 +648,22 @@ int ParseIdentifier(ParsePtr p, DynamicBuffer *dbuf)
int EvaluateExpr(ParsePtr p, Value *v) int EvaluateExpr(ParsePtr p, Value *v)
{ {
int bracketed = 0;
int r; int r;
int nonconst = 0;
expr_node *node = ParseExpr(p, &r);
if (p->isnested) return E_PARSE_ERR; /* Can't nest expressions */ if (r != OK) {
if (!p->pos) return E_PARSE_ERR; /* Missing expression */ return r;
while (isempty(*p->pos)) (p->pos)++;
if (*p->pos == BEG_OF_EXPR) {
(p->pos)++;
bracketed = 1;
} }
r = EvalExpr(&(p->pos), v, p); if (!node) {
return E_SWERR;
}
r = evaluate_expr_node(node, NULL, v, &nonconst);
free_expr_tree(node);
if (r) return r; if (r) return r;
if (bracketed) { if (nonconst) {
if (*p->pos != END_OF_EXPR) return E_MISS_END; p->nonconst_expr = 1;
(p->pos)++;
} }
return OK; return OK;
} }
@@ -651,27 +707,34 @@ void Eprint(char const *fmt, ...)
FreshLine = 0; FreshLine = 0;
if (strcmp(FileName, "-")) { if (strcmp(FileName, "-")) {
(void) fprintf(ErrFp, "%s(%d): ", FileName, LineNo); (void) fprintf(ErrFp, "%s(%d): ", FileName, LineNo);
va_start(argptr, fmt);
(void) vfprintf(ErrFp, fmt, argptr);
(void) fputc('\n', ErrFp);
va_end(argptr);
if (print_callstack(ErrFp)) { if (print_callstack(ErrFp)) {
(void) fprintf(ErrFp, ": "); (void) fprintf(ErrFp, "\n");
} }
} else { } else {
(void) fprintf(ErrFp, "-stdin-(%d): ", LineNo); (void) fprintf(ErrFp, "-stdin-(%d): ", LineNo);
va_start(argptr, fmt);
(void) vfprintf(ErrFp, fmt, argptr);
(void) fputc('\n', ErrFp);
va_end(argptr);
if (print_callstack(ErrFp)) { if (print_callstack(ErrFp)) {
(void) fprintf(ErrFp, ": "); (void) fprintf(ErrFp, "\n");
} }
} }
if (DebugFlag & DB_PRTLINE) OutputLine(ErrFp); if (DebugFlag & DB_PRTLINE) OutputLine(ErrFp);
} else if (FileName) { } else if (FileName) {
fprintf(ErrFp, " "); fprintf(ErrFp, " ");
va_start(argptr, fmt);
(void) vfprintf(ErrFp, fmt, argptr);
(void) fputc('\n', ErrFp);
va_end(argptr);
if (print_callstack(ErrFp)) { if (print_callstack(ErrFp)) {
(void) fprintf(ErrFp, ": "); (void) fprintf(ErrFp, "\n");
} }
} }
va_start(argptr, fmt);
(void) vfprintf(ErrFp, fmt, argptr);
(void) fputc('\n', ErrFp);
va_end(argptr);
return; return;
} }
@@ -1025,8 +1088,8 @@ int DoDebug(ParsePtr p)
case 's': case 's':
case 'S': case 'S':
if (val) DebugFlag |= DB_EXPR_STACKS; if (val) DebugFlag |= DB_PARSE_EXPR;
else DebugFlag &= ~DB_EXPR_STACKS; else DebugFlag &= ~DB_PARSE_EXPR;
break; break;
case 'x': case 'x':

View File

@@ -43,6 +43,7 @@
int CallUserFunc (char const *name, int nargs, ParsePtr p); int CallUserFunc (char const *name, int nargs, ParsePtr p);
int DoFset (ParsePtr p); int DoFset (ParsePtr p);
int DoFunset (ParsePtr p); int DoFunset (ParsePtr p);
void UnsetAllUserFuncs(void);
void ProduceCalendar (void); void ProduceCalendar (void);
char const *SimpleTime (int tim); char const *SimpleTime (int tim);
char const *CalendarTime (int tim, int duration); char const *CalendarTime (int tim, int duration);
@@ -56,9 +57,12 @@ int DoSubst (ParsePtr p, DynamicBuffer *dbuf, Trigger *t, TimeTrig *tt, int dse,
int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int dse, int tim); int DoSubstFromString (char const *source, DynamicBuffer *dbuf, int dse, int tim);
int ParseLiteralDate (char const **s, int *dse, int *tim); int ParseLiteralDate (char const **s, int *dse, int *tim);
int ParseLiteralTime (char const **s, int *tim); int ParseLiteralTime (char const **s, int *tim);
int evaluate_expr_node(expr_node *node, Value *locals, Value *ans, int *nonconst);
void print_expr_tree(expr_node *node, FILE *fp);
expr_node *free_expr_tree(expr_node *node);
int EvalExpr (char const **e, Value *v, ParsePtr p); int EvalExpr (char const **e, Value *v, ParsePtr p);
int DoCoerce (char type, Value *v); int DoCoerce (char type, Value *v);
void PrintValue (Value *v, FILE *fp); char const *PrintValue (Value *v, FILE *fp);
int CopyValue (Value *dest, const Value *src); int CopyValue (Value *dest, const Value *src);
int ReadLine (void); int ReadLine (void);
int OpenFile (char const *fname); int OpenFile (char const *fname);
@@ -77,8 +81,9 @@ int JulianToGregorianOffset(int y, int m);
int ParseChar (ParsePtr p, int *err, int peek); int ParseChar (ParsePtr p, int *err, int peek);
int ParseToken (ParsePtr p, DynamicBuffer *dbuf); int ParseToken (ParsePtr p, DynamicBuffer *dbuf);
int ParseIdentifier (ParsePtr p, DynamicBuffer *dbuf); int ParseIdentifier (ParsePtr p, DynamicBuffer *dbuf);
expr_node * ParseExpr(ParsePtr p, int *r);
void print_expr_nodes_stats(void);
int EvaluateExpr (ParsePtr p, Value *v); int EvaluateExpr (ParsePtr p, Value *v);
int Evaluate (char const **s, Var *locals, ParsePtr p);
int FnPopValStack (Value *val); int FnPopValStack (Value *val);
void Eprint (char const *fmt, ...); void Eprint (char const *fmt, ...);
void Wprint (char const *fmt, ...); void Wprint (char const *fmt, ...);
@@ -129,9 +134,10 @@ int StrCmpi (char const *s1, char const *s2);
#endif #endif
Var *FindVar (char const *str, int create); Var *FindVar (char const *str, int create);
SysVar *FindSysVar (char const *name);
int DeleteVar (char const *str); int DeleteVar (char const *str);
int SetVar (char const *str, Value const *val); int SetVar (char const *str, Value const *val);
int GetVarValue (char const *str, Value *val, Var *locals, ParsePtr p); int GetVarValue (char const *str, Value *val);
int DoSet (Parser *p); int DoSet (Parser *p);
int DoUnset (Parser *p); int DoUnset (Parser *p);
int DoDump (ParsePtr p); int DoDump (ParsePtr p);
@@ -145,9 +151,10 @@ int ParseNonSpaceChar (ParsePtr p, int *err, int peek);
unsigned int HashVal (char const *str); unsigned int HashVal (char const *str);
int DateOK (int y, int m, int d); int DateOK (int y, int m, int d);
Operator *FindOperator (char const *name, Operator where[], int num); Operator *FindOperator (char const *name, Operator where[], int num);
BuiltinFunc *FindFunc (char const *name, BuiltinFunc where[], int num); BuiltinFunc *FindBuiltinFunc (char const *name);
int InsertIntoSortBuffer (int dse, int tim, char const *body, int typ, int prio); int InsertIntoSortBuffer (int dse, int tim, char const *body, int typ, int prio);
void IssueSortedReminders (void); void IssueSortedReminders (void);
UserFunc *FindUserFunc(char const *name);
int UserFuncExists (char const *fn); int UserFuncExists (char const *fn);
void DSEToHeb (int dse, int *hy, int *hm, int *hd); void DSEToHeb (int dse, int *hy, int *hm, int *hd);
int HebNameToNum (char const *mname); int HebNameToNum (char const *mname);
@@ -207,6 +214,7 @@ void set_cloexec(FILE *fp);
int push_call(char const *filename, char const *func, int lineno); int push_call(char const *filename, char const *func, int lineno);
void clear_callstack(void); void clear_callstack(void);
int print_callstack(FILE *fp); int print_callstack(FILE *fp);
int have_callstack(void);
void pop_call(void); void pop_call(void);
void FixSpecialType(Trigger *trig); void FixSpecialType(Trigger *trig);
void WriteJSONTrigger(Trigger const *t, int include_tags, int today); void WriteJSONTrigger(Trigger const *t, int include_tags, int today);

View File

@@ -30,21 +30,62 @@ typedef struct {
int (*func)(void); int (*func)(void);
} Operator; } Operator;
/* New-style expr_node structure and constants */
enum expr_node_type
{
N_FREE,
N_ERROR,
N_CONSTANT,
N_LOCAL_VAR,
N_SHORT_VAR,
N_VARIABLE,
N_SHORT_SYSVAR,
N_SYSVAR,
N_BUILTIN_FUNC,
N_SHORT_USER_FUNC,
N_USER_FUNC,
N_BINARY_OPERATOR,
N_UNARY_OPERATOR,
};
/* Structure for passing in Nargs and out RetVal from functions */ /* Structure for passing in Nargs and out RetVal from functions */
typedef struct { typedef struct {
int nargs; int nargs;
Value *args;
Value retval; Value retval;
} func_info; } func_info;
/* Forward reference */
typedef struct expr_node_struct expr_node;
/* Define the type of user-functions */ /* Define the type of user-functions */
typedef struct { typedef struct {
char const *name; char const *name;
char minargs; char minargs;
char maxargs; char maxargs;
char is_constant; char is_constant;
/* Old-style function calling convention */
int (*func)(func_info *); int (*func)(func_info *);
/* New-style function calling convention */
int (*newfunc)(expr_node *node, Value *locals, Value *ans, int *nonconst);
} BuiltinFunc; } BuiltinFunc;
#define SHORT_NAME_BUF 16
typedef struct expr_node_struct {
struct expr_node_struct *child;
struct expr_node_struct *sibling;
enum expr_node_type type;
int num_kids;
union {
Value value;
int arg;
BuiltinFunc *builtin_func;
char name[SHORT_NAME_BUF];
int (*operator_func) (struct expr_node_struct *node, Value *locals, Value *ans, int *nonconst);
} u;
} expr_node;
/* Define the structure of a variable */ /* Define the structure of a variable */
typedef struct var { typedef struct var {
struct var *next; struct var *next;
@@ -142,6 +183,8 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
#define MSF_TYPE 7 #define MSF_TYPE 7
#define PASSTHRU_TYPE 8 #define PASSTHRU_TYPE 8
/* For function arguments */
#define NO_MAX 127
/* DEFINES for debugging flags */ /* DEFINES for debugging flags */
#define DB_PRTLINE 1 #define DB_PRTLINE 1
@@ -150,7 +193,7 @@ typedef Parser *ParsePtr; /* Pointer to parser structure */
#define DB_DUMP_VARS 8 #define DB_DUMP_VARS 8
#define DB_ECHO_LINE 16 #define DB_ECHO_LINE 16
#define DB_TRACE_FILES 32 #define DB_TRACE_FILES 32
#define DB_EXPR_STACKS 64 #define DB_PARSE_EXPR 64
/* Enumeration of the tokens */ /* Enumeration of the tokens */
enum TokTypes enum TokTypes
@@ -244,3 +287,26 @@ typedef struct {
#define TERMINAL_BACKGROUND_UNKNOWN -1 #define TERMINAL_BACKGROUND_UNKNOWN -1
#define TERMINAL_BACKGROUND_DARK 0 #define TERMINAL_BACKGROUND_DARK 0
#define TERMINAL_BACKGROUND_LIGHT 1 #define TERMINAL_BACKGROUND_LIGHT 1
typedef int (*SysVarFunc)(int, Value *);
/* The structure of a system variable */
typedef struct {
char const *name;
char modifiable;
int type;
void *value;
int min; /* Or const-value */
int max;
} SysVar;
/* Define the data structure used to hold a user-defined function */
typedef struct udf_struct {
struct udf_struct *next;
char name[VAR_NAME_LEN+1];
expr_node *node;
char **args;
int nargs;
char const *filename;
int lineno;
} UserFunc;

View File

@@ -30,34 +30,12 @@
#define FUNC_HASH_SIZE 32 /* Size of User-defined function hash table */ #define FUNC_HASH_SIZE 32 /* Size of User-defined function hash table */
/* Define the data structure used to hold a user-defined function */
typedef struct udf_struct {
struct udf_struct *next;
char name[VAR_NAME_LEN+1];
char const *text;
Var *locals;
char IsActive;
int nargs;
char const *filename;
int lineno;
} UserFunc;
/* The hash table */ /* The hash table */
static UserFunc *FuncHash[FUNC_HASH_SIZE]; static UserFunc *FuncHash[FUNC_HASH_SIZE];
/* Access to built-in functions */
extern int NumFuncs;
extern BuiltinFunc Func[];
/* We need access to the expression evaluation stack */
extern Value ValStack[];
extern int ValStackPtr;
static void DestroyUserFunc (UserFunc *f); static void DestroyUserFunc (UserFunc *f);
static void FUnset (char const *name); static void FUnset (char const *name);
static void FSet (UserFunc *f); static void FSet (UserFunc *f);
static int SetUpLocalVars (UserFunc *f);
static void DestroyLocalVals (UserFunc *f);
/***************************************************************/ /***************************************************************/
/* */ /* */
@@ -98,9 +76,11 @@ int DoFset(ParsePtr p)
{ {
int r; int r;
int c; int c;
int i;
UserFunc *func; UserFunc *func;
Var *v; UserFunc *existing;
Var *local; Var *locals = NULL;
Var local_array[MAX_FUNC_ARGS];
int orig_namelen; int orig_namelen;
DynamicBuffer buf; DynamicBuffer buf;
@@ -125,6 +105,18 @@ int DoFset(ParsePtr p)
return E_PARSE_ERR; return E_PARSE_ERR;
} }
/* If the function exists and was defined at the same line of the same
file, do nothing */
existing = FindUserFunc(DBufValue(&buf));
if (existing) {
if (!strcmp(existing->filename, FileName) &&
strcmp(existing->filename, "[cmdline]") &&
existing->lineno == LineNo) {
DBufFree(&buf);
/* We already have it! Our work here is done. */
return OK;
}
}
func = NEW(UserFunc); func = NEW(UserFunc);
if (!func) { if (!func) {
DBufFree(&buf); DBufFree(&buf);
@@ -143,25 +135,22 @@ int DoFset(ParsePtr p)
StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN); StrnCpy(func->name, DBufValue(&buf), VAR_NAME_LEN);
DBufFree(&buf); DBufFree(&buf);
if (!Hush) { if (!Hush) {
if (FindFunc(func->name, Func, NumFuncs)) { if (FindBuiltinFunc(func->name)) {
Eprint("%s: `%s'", ErrMsg[E_REDEF_FUNC], func->name); Eprint("%s: `%s'", ErrMsg[E_REDEF_FUNC], func->name);
} }
} }
func->locals = NULL; func->node = NULL;
func->text = NULL;
func->IsActive = 0;
func->nargs = 0; func->nargs = 0;
func->args = NULL;
/* Get the local variables - we insert the local variables in REVERSE /* Get the local variables */
order, but that's OK, because we pop them off the stack in reverse
order, too, so everything works out just fine. */
c=ParseNonSpaceChar(p, &r, 1); c=ParseNonSpaceChar(p, &r, 1);
if (r) return r; if (r) return r;
if (c == ')') { if (c == ')') {
(void) ParseNonSpaceChar(p, &r, 0); (void) ParseNonSpaceChar(p, &r, 0);
} } else {
else { locals = local_array;
while(1) { while(1) {
if ( (r=ParseIdentifier(p, &buf)) ) return r; if ( (r=ParseIdentifier(p, &buf)) ) return r;
if (*DBufValue(&buf) == '$') { if (*DBufValue(&buf) == '$') {
@@ -170,27 +159,24 @@ int DoFset(ParsePtr p)
return E_BAD_ID; return E_BAD_ID;
} }
/* If we've already seen this local variable, error */ /* If we've already seen this local variable, error */
local = func->locals; for (i=0; i<func->nargs; i++) {
while(local) { if (!StrinCmp(DBufValue(&buf), local_array[i].name, VAR_NAME_LEN)) {
if (!StrinCmp(DBufValue(&buf), local->name, VAR_NAME_LEN)) {
DBufFree(&buf); DBufFree(&buf);
DestroyUserFunc(func); DestroyUserFunc(func);
return E_REPEATED_ARG; return E_REPEATED_ARG;
} }
local = local->next;
} }
v = NEW(Var); i = func->nargs;
if (!v) { if (i >= MAX_FUNC_ARGS-1) {
DBufFree(&buf); DBufFree(&buf);
DestroyUserFunc(func); DestroyUserFunc(func);
return E_NO_MEM; return E_2MANY_ARGS;
} }
local_array[i].v.type = ERR_TYPE;
StrnCpy(local_array[i].name, DBufValue(&buf), VAR_NAME_LEN);
local_array[i].next = &(local_array[i+1]);
local_array[i+1].next = NULL;
func->nargs++; func->nargs++;
v->v.type = ERR_TYPE;
StrnCpy(v->name, DBufValue(&buf), VAR_NAME_LEN);
DBufFree(&buf);
v->next = func->locals;
func->locals = v;
c = ParseNonSpaceChar(p, &r, 0); c = ParseNonSpaceChar(p, &r, 0);
if (c == ')') break; if (c == ')') break;
else if (c != ',') { else if (c != ',') {
@@ -205,7 +191,6 @@ int DoFset(ParsePtr p)
if (c == '=') { if (c == '=') {
(void) ParseNonSpaceChar(p, &r, 0); (void) ParseNonSpaceChar(p, &r, 0);
} }
/* Copy the text over */
if (p->isnested) { if (p->isnested) {
Eprint("%s", ErrMsg[E_CANTNEST_FDEF]); Eprint("%s", ErrMsg[E_CANTNEST_FDEF]);
DestroyUserFunc(func); DestroyUserFunc(func);
@@ -219,10 +204,23 @@ int DoFset(ParsePtr p)
DestroyUserFunc(func); DestroyUserFunc(func);
return E_EOLN; return E_EOLN;
} }
func->text = StrDup(p->pos); /* Parse the expression */
if (!func->text) { func->node = parse_expression(&(p->pos), &r, locals);
DestroyUserFunc(func); if (!func->node) {
return E_NO_MEM; DestroyUserFunc(func);
return r;
}
/* Save the argument names */
if (func->nargs) {
func->args = calloc(sizeof(char *), func->nargs);
for (i=0; i<func->nargs; i++) {
func->args[i] = StrDup(local_array[i].name);
if (!func->args[i]) {
DestroyUserFunc(func);
return E_NO_MEM;
}
}
} }
/* If an old definition of this function exists, destroy it */ /* If an old definition of this function exists, destroy it */
@@ -246,23 +244,22 @@ int DoFset(ParsePtr p)
/***************************************************************/ /***************************************************************/
static void DestroyUserFunc(UserFunc *f) static void DestroyUserFunc(UserFunc *f)
{ {
Var *v, *prev; int i;
/* Free the local variables first */
v = f->locals;
while(v) {
DestroyValue(v->v);
prev = v;
v = v->next;
free(prev);
}
/* Free the function definition */ /* Free the function definition */
if (f->text) free( (char *) f->text); if (f->node) free_expr_tree(f->node);
/* Free the filename */ /* Free the filename */
if (f->filename) free( (char *) f->filename); if (f->filename) free( (char *) f->filename);
/* Free arg names */
if (f->args) {
for (i=0; i<f->nargs; i++) {
if (f->args[i]) free(f->args[i]);
}
free(f->args);
}
/* Free the data structure itself */ /* Free the data structure itself */
free(f); free(f);
} }
@@ -308,129 +305,17 @@ static void FSet(UserFunc *f)
FuncHash[h] = f; FuncHash[h] = f;
} }
/***************************************************************/ UserFunc *FindUserFunc(char const *name)
/* */
/* CallUserFunc */
/* */
/* Call a user-defined function. */
/* */
/***************************************************************/
int CallUserFunc(char const *name, int nargs, ParsePtr p)
{ {
UserFunc *f; UserFunc *f;
int h = HashVal(name) % FUNC_HASH_SIZE; int h = HashVal(name) % FUNC_HASH_SIZE;
int i;
char const *s;
/* Search for the function */ /* Search for the function */
f = FuncHash[h]; f = FuncHash[h];
while (f && StrinCmp(name, f->name, VAR_NAME_LEN)) f = f->next; while (f && StrinCmp(name, f->name, VAR_NAME_LEN)) f = f->next;
if (!f) { return f;
Eprint("%s: `%s'", ErrMsg[E_UNDEF_FUNC], name);
return E_UNDEF_FUNC;
}
/* Debugging stuff */
if (DebugFlag & DB_PRTEXPR) {
fprintf(ErrFp, "%s %s(", ErrMsg[E_ENTER_FUN], f->name);
for (i=0; i<nargs; i++) {
PrintValue(&ValStack[ValStackPtr - nargs + i], ErrFp);
if (i<nargs-1) fprintf(ErrFp, ", ");
}
fprintf(ErrFp, ")\n");
}
/* Detect illegal recursive call */
if (f->IsActive) {
if (DebugFlag &DB_PRTEXPR) {
fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
fprintf(ErrFp, "%s\n", ErrMsg[E_RECURSIVE]);
}
return E_RECURSIVE;
}
/* Check number of args */
if (nargs != f->nargs) {
if (DebugFlag &DB_PRTEXPR) {
fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
fprintf(ErrFp, "%s\n",
ErrMsg[(nargs < f->nargs) ? E_2FEW_ARGS : E_2MANY_ARGS]);
}
return (nargs < f->nargs) ? E_2FEW_ARGS : E_2MANY_ARGS;
}
/* Found the function - set up a local variable frame */
h = SetUpLocalVars(f);
if (h) {
if (DebugFlag &DB_PRTEXPR) {
fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
fprintf(ErrFp, "%s\n", ErrMsg[h]);
}
return h;
}
/* Evaluate the expression */
f->IsActive = 1;
s = f->text;
/* Skip the opening bracket, if there's one */
while (isempty(*s)) s++;
if (*s == BEG_OF_EXPR) {
s++;
}
push_call(f->filename, f->name, f->lineno);
h = Evaluate(&s, f->locals, p);
if (h == OK) {
pop_call();
}
f->IsActive = 0;
DestroyLocalVals(f);
if (DebugFlag &DB_PRTEXPR) {
fprintf(ErrFp, "%s %s() => ", ErrMsg[E_LEAVE_FUN], name);
if (h) fprintf(ErrFp, "%s\n", ErrMsg[h]);
else {
PrintValue(&ValStack[ValStackPtr-1], ErrFp);
fprintf(ErrFp, "\n");
}
}
return h;
} }
/***************************************************************/
/* */
/* SetUpLocalVars */
/* */
/* Set up the local variables from the stack frame. */
/* */
/***************************************************************/
static int SetUpLocalVars(UserFunc *f)
{
int i, r;
Var *var;
for (i=0, var=f->locals; var && i<f->nargs; var=var->next, i++) {
if ( (r=FnPopValStack(&(var->v))) ) {
DestroyLocalVals(f);
return r;
}
}
return OK;
}
/***************************************************************/
/* */
/* DestroyLocalVals */
/* */
/* Destroy the values of all local variables after evaluating */
/* the function. */
/* */
/***************************************************************/
static void DestroyLocalVals(UserFunc *f)
{
Var *v = f->locals;
while(v) {
DestroyValue(v->v);
v = v->next;
}
}
/***************************************************************/ /***************************************************************/
/* */ /* */
/* UserFuncExists */ /* UserFuncExists */
@@ -441,12 +326,33 @@ static void DestroyLocalVals(UserFunc *f)
/***************************************************************/ /***************************************************************/
int UserFuncExists(char const *fn) int UserFuncExists(char const *fn)
{ {
UserFunc *f; UserFunc *f = FindUserFunc(fn);
int h = HashVal(fn) % FUNC_HASH_SIZE;
f = FuncHash[h];
while (f && StrinCmp(fn, f->name, VAR_NAME_LEN)) f = f->next;
if (!f) return -1; if (!f) return -1;
else return f->nargs; else return f->nargs;
} }
/***************************************************************/
/* */
/* UnsetAllUserFuncs */
/* */
/* Call FUNSET on all user funcs. Used with -ds flag to */
/* ensure no expr_node memory leaks. */
/* */
/***************************************************************/
void
UnsetAllUserFuncs(void)
{
UserFunc *f;
UserFunc *next;
int i;
for (i=0; i<FUNC_HASH_SIZE; i++) {
f = FuncHash[i];
while(f) {
next = f->next;
DestroyUserFunc(f);
f = next;
}
FuncHash[i] = NULL;
}
}

View File

@@ -187,31 +187,33 @@ typedef struct cs_s {
} cs; } cs;
static cs *callstack = NULL; static cs *callstack = NULL;
static cs *freecs = NULL;
static void static void
destroy_cs(cs *entry) destroy_cs(cs *entry)
{ {
if (entry->filename) free( (void *) entry->filename); entry->next = freecs;
if (entry->func) free( (void *) entry->func); freecs = entry;
free( (void *) entry);
} }
int int
push_call(char const *filename, char const *func, int lineno) push_call(char const *filename, char const *func, int lineno)
{ {
cs *entry = NEW(cs); cs *entry;
if (!entry) { if (freecs) {
return E_NO_MEM; entry = freecs;
freecs = freecs->next;
} else {
entry = NEW(cs);
if (!entry) {
return E_NO_MEM;
}
} }
entry->next = NULL; entry->next = NULL;
entry->filename = StrDup(filename); entry->filename = filename;
entry->func = StrDup(func); entry->func = func;
entry->lineno = lineno; entry->lineno = lineno;
if (!entry->filename || !entry->func) {
destroy_cs(entry);
return E_NO_MEM;
}
entry->next = callstack; entry->next = callstack;
callstack = entry; callstack = entry;
return OK; return OK;
@@ -233,11 +235,31 @@ clear_callstack(void)
static void static void
print_callstack_aux(FILE *fp, cs *entry) print_callstack_aux(FILE *fp, cs *entry)
{ {
if (entry) { int i = 0;
print_callstack_aux(fp, entry->next); char const *in = "In";
fprintf(fp, "\n"); cs *prev = NULL;
(void) fprintf(fp, "%s(%d): In function `%s'", entry->filename, entry->lineno, entry->func); while(entry) {
if (prev) {
fprintf(fp, "\n");
in = "Called from";
}
(void) fprintf(fp, " %s(%d): [#%d] %s function `%s'", entry->filename, entry->lineno, i, in, entry->func);
prev = entry;
entry = entry->next;
i++;
if (i > 10) {
break;
}
} }
if (entry) {
(void) fprintf(fp, "\n [remaining call frames omitted]");
}
}
int
have_callstack(void)
{
return (callstack != NULL);
} }
int int

View File

@@ -39,8 +39,6 @@ static int IntMax = INT_MAX;
static Var *VHashTbl[VAR_HASH_SIZE]; static Var *VHashTbl[VAR_HASH_SIZE];
typedef int (*SysVarFunc)(int, Value *);
static double static double
strtod_in_c_locale(char const *str, char **endptr) strtod_in_c_locale(char const *str, char **endptr)
{ {
@@ -511,20 +509,10 @@ int SetVar(char const *str, Value const *val)
/* Get a copy of the value of the variable. */ /* Get a copy of the value of the variable. */
/* */ /* */
/***************************************************************/ /***************************************************************/
int GetVarValue(char const *str, Value *val, Var *locals, ParsePtr p) int GetVarValue(char const *str, Value *val)
{ {
Var *v; Var *v;
/* Try searching local variables first */
v = locals;
while (v) {
if (! StrinCmp(str, v->name, VAR_NAME_LEN))
return CopyValue(val, &v->v);
v = v->next;
}
/* Global variable... mark expression as non-constant */
if (p) p->nonconst_expr = 1;
v=FindVar(str, 0); v=FindVar(str, 0);
if (!v) { if (!v) {
@@ -785,16 +773,6 @@ int DoPreserve (Parser *p)
/* */ /* */
/***************************************************************/ /***************************************************************/
/* The structure of a system variable */
typedef struct {
char const *name;
char modifiable;
int type;
void *value;
int min; /* Or const-value */
int max;
} SysVar;
/* Macro to access "min" but as a constval. Just to make source more /* Macro to access "min" but as a constval. Just to make source more
readable */ readable */
#define constval min #define constval min
@@ -919,7 +897,6 @@ static SysVar SysVarArr[] = {
}; };
#define NUMSYSVARS ( sizeof(SysVarArr) / sizeof(SysVar) ) #define NUMSYSVARS ( sizeof(SysVarArr) / sizeof(SysVar) )
static SysVar *FindSysVar (char const *name);
static void DumpSysVar (char const *name, const SysVar *v); static void DumpSysVar (char const *name, const SysVar *v);
/***************************************************************/ /***************************************************************/
/* */ /* */
@@ -1016,7 +993,7 @@ int GetSysVar(char const *name, Value *val)
/* Find a system var with specified name. */ /* Find a system var with specified name. */
/* */ /* */
/***************************************************************/ /***************************************************************/
static SysVar *FindSysVar(char const *name) SysVar *FindSysVar(char const *name)
{ {
int top=NUMSYSVARS-1, bottom=0; int top=NUMSYSVARS-1, bottom=0;
int mid=(top + bottom) / 2; int mid=(top + bottom) / 2;

View File

@@ -35,8 +35,8 @@ set a ansicolor(-1, 0, 0)
set a ansicolor(42, 42, 256) set a ansicolor(42, 42, 256)
set a ansicolor("foo") set a ansicolor("foo")
set a ansicolor("1 1") set a ansicolor("1 1")
set a ansicolor("-1 -1 0"); set a ansicolor("-1 -1 0")
set a ansicolor("256 1 1"); set a ansicolor("256 1 1")
set a ansicolor(128, 128, 128, 2) set a ansicolor(128, 128, 128, 2)
set a ansicolor(128, 128, 128, -1) set a ansicolor(128, 128, 128, -1)
set a ansicolor(128, 128, 128, 0, 2) set a ansicolor(128, 128, 128, 0, 2)