forked from epics_driver_modules/require
expressions moved to separate file
This commit is contained in:
@@ -10,6 +10,8 @@ SOURCES += require.c
|
||||
DBDS += require.dbd
|
||||
SOURCES += runScript.c
|
||||
DBDS += runScript.dbd
|
||||
SOURCES += expr.c
|
||||
#DBDS += expr.dbd
|
||||
|
||||
SOURCES += dbLoadTemplate.y
|
||||
DBDS += dbLoadTemplate.dbd
|
||||
|
||||
@@ -13,6 +13,9 @@ requireSup_DBD += require.dbd
|
||||
LIB_SRCS += runScript.c
|
||||
requireSup_DBD += runScript.dbd
|
||||
|
||||
LIB_SRCS += expr.c
|
||||
#requireSup_DBD += expr.dbd
|
||||
|
||||
LIB_SRCS += dbLoadTemplate.y
|
||||
requireSup_DBD += dbLoadTemplate.dbd
|
||||
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "expr.h"
|
||||
|
||||
int exprDebug;
|
||||
|
||||
static int parseExpr(const char** pp, long* v, int op);
|
||||
|
||||
static int parseValue(const char** pp, long* v)
|
||||
{
|
||||
long val;
|
||||
const char *p = *pp;
|
||||
char o;
|
||||
|
||||
/* A value is optionally prefixed with an unary operator + - ! ~.
|
||||
* It is either a number (decimal, octal or hex)
|
||||
* or an expression in ().
|
||||
* Allowed chars after a number: operators, closing parenthesis, whitespace, quotes, end of string
|
||||
*/
|
||||
|
||||
/* first look for value */
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
o = *p;
|
||||
if (memchr("+-~!", o, 4))
|
||||
{
|
||||
/* handle unary operators */
|
||||
p++;
|
||||
if (!parseValue(&p, &val)) return 0; /* no valid value */
|
||||
if (o == '-') val=-val;
|
||||
else if (o == '~') val=~val;
|
||||
else if (o == '!') val=!val;
|
||||
}
|
||||
else if (o == '(')
|
||||
{
|
||||
/* handle sub-expression */
|
||||
p++;
|
||||
if (parseExpr(&p, &val, 0) < 0) return 0; /* no valid expression */
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (*p++ != ')') return 0; /* missing ) */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* get number */
|
||||
char* e;
|
||||
val = strtol(p, &e, 0);
|
||||
if (e == p) return 0; /* no number */
|
||||
|
||||
if (isalpha((unsigned char)*p))
|
||||
{
|
||||
/* followed by rubbish */
|
||||
return 0;
|
||||
}
|
||||
p = e;
|
||||
}
|
||||
*pp = p;
|
||||
*v = val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static long ipow(long base, long exp)
|
||||
{
|
||||
long v;
|
||||
if (exp < 0) return 0;
|
||||
if (exp == 0) return 1;
|
||||
v = base;
|
||||
while (--exp) v *= base; /* optimize this! */
|
||||
return v;
|
||||
}
|
||||
|
||||
struct {char str[4]; int pr;} ops[] = {
|
||||
{"<-",0},
|
||||
{"**",11},
|
||||
{"*", 10},{"/",10},{"%",10},
|
||||
{"+",9},{"-",9},
|
||||
{"<<",8},{">>>",8},{">>",8},
|
||||
{"<=>",7},{"<=",7},{">=",7},{"<",7},{">",7},
|
||||
{"==",6},{"!=",6},
|
||||
{"&&",5},{"||",5},
|
||||
{"&",4},{"^",3},{"|",2},{"?",1}
|
||||
};
|
||||
|
||||
static int startsWith(const char* p, const char* s)
|
||||
{
|
||||
int i = 0;
|
||||
while (*s) { i++; if (*p++ != *s++) return 0; }
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parseOp(const char** pp)
|
||||
{
|
||||
const char *p = *pp;
|
||||
int o, l;
|
||||
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (ispunct((unsigned char)*p))
|
||||
{
|
||||
for (o = 1; o < (int)(sizeof(ops)/sizeof(ops[0])); o++)
|
||||
{
|
||||
if ((l = startsWith(p, ops[o].str)))
|
||||
{
|
||||
/* operator found */
|
||||
*pp = p+l;
|
||||
return o;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parseExpr(const char** pp, long* v, int o)
|
||||
{
|
||||
const char *p = *pp;
|
||||
long val = *v;
|
||||
long val2;
|
||||
int o2 = o;
|
||||
int pr = ops[o].pr;
|
||||
|
||||
if (exprDebug) printf("parseExpr(%s %d): start %ld %s %s\n", ops[o].str, pr, val, ops[o].str, p);
|
||||
do {
|
||||
if (!parseValue(&p, &val2)) return -1;
|
||||
if ((o2 = parseOp(&p)))
|
||||
{
|
||||
if (exprDebug) printf("parseExpr(%d): %ld %s %ld %s %s\n", pr, val, ops[o].str, val2, ops[o2].str, p);
|
||||
if (o && ops[o2].pr > ops[o].pr)
|
||||
{
|
||||
if ((o2 = parseExpr(&p, &val2, o2)) < 0) return -1;
|
||||
}
|
||||
}
|
||||
if (exprDebug) printf("parseExpr(%d): %ld %s %ld", pr, val, ops[o].str, val2);
|
||||
switch(o)
|
||||
{
|
||||
case 0: val = val2; break;
|
||||
case 1: val = ipow(val, val2); break;
|
||||
case 2: val *= val2; break;
|
||||
case 3: val /= val2; break;
|
||||
case 4: val %= val2; break;
|
||||
case 5: val += val2; break;
|
||||
case 6: val -= val2; break;
|
||||
case 7: val <<= val2; break;
|
||||
case 8: val = (unsigned long)val >> val2; break;
|
||||
case 9: val >>= val2; break;
|
||||
case 10: val = val < val2 ? -1 : val == val2 ? 0 : 1; break;
|
||||
case 11: val = val <= val2; break;
|
||||
case 12: val = val >= val2; break;
|
||||
case 13: val = val < val2; break;
|
||||
case 14: val = val > val2; break;
|
||||
case 15: val = val == val2; break;
|
||||
case 16: val = val != val2; break;
|
||||
case 17: val = val && val2; break;
|
||||
case 18: val = val || val2; break;
|
||||
case 19: val &= val2; break;
|
||||
case 20: val ^= val2; break;
|
||||
case 21: val |= val2; break;
|
||||
case 22: val = (val != 0); break;
|
||||
}
|
||||
if (exprDebug) printf(" = %ld\n", val);
|
||||
o = o2;
|
||||
} while (o && pr <= ops[o].pr);
|
||||
if (exprDebug) printf("parseExpr(%d): result %ld\n", pr, val);
|
||||
*pp = p;
|
||||
*v = val;
|
||||
return o;
|
||||
}
|
||||
|
||||
const char* getFormat(const char** pp)
|
||||
{
|
||||
static char format [20];
|
||||
const char* p = *pp;
|
||||
unsigned int i = 1;
|
||||
if (exprDebug) printf("getFormat %s\n", p);
|
||||
if ((format[0] = *p++) == '%')
|
||||
{
|
||||
while (i < sizeof(format) && memchr(" #-+0", *p, 5))
|
||||
format[i++] = *p++;
|
||||
while (i < sizeof(format) && *p >= '0' && *p <= '9')
|
||||
format[i++] = *p++;
|
||||
if (i < sizeof(format))
|
||||
format[i++] = 'l';
|
||||
if (i < sizeof(format) && memchr("diouxXc", *p, 7))
|
||||
{
|
||||
format[i++] = *p++;
|
||||
format[i] = 0;
|
||||
*pp = p;
|
||||
if (exprDebug) printf("format = '%s'\n", format);
|
||||
return format;
|
||||
}
|
||||
}
|
||||
if (exprDebug) printf("no format\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t replaceExpressions(const char* r, char* buffer, size_t buffersize)
|
||||
{
|
||||
long val;
|
||||
char* w = buffer;
|
||||
char* s;
|
||||
|
||||
while (*r)
|
||||
{
|
||||
s = w;
|
||||
if (*r == '"' || *r == '\'')
|
||||
{
|
||||
/* quoted strings */
|
||||
char c = *w++ = *r++;
|
||||
while (*r && *r != c) {
|
||||
if (*r == '\\' && !(*w++ = *r++)) break;
|
||||
*w++ = *r++;
|
||||
}
|
||||
if (*r) *w++ = *r++;
|
||||
*w = 0;
|
||||
if (exprDebug) printf("quoted string %s\n", s);
|
||||
}
|
||||
else if (*r == '%')
|
||||
{
|
||||
/* formatted expression */
|
||||
const char* r2 = r;
|
||||
const char* f;
|
||||
if (exprDebug) printf("formatted expression after '%s'\n", s);
|
||||
if ((f = getFormat(&r2)) && parseExpr(&r2, &val, 0) == 0)
|
||||
{
|
||||
r = r2;
|
||||
if (*s == '(' && *r2++ == ')')
|
||||
{
|
||||
w = s;
|
||||
r = r2;
|
||||
}
|
||||
w += sprintf(w, f , val);
|
||||
if (exprDebug) printf("formatted expression %s\n", s);
|
||||
}
|
||||
}
|
||||
else if (parseExpr(&r, &val, 0) == 0)
|
||||
{
|
||||
/* unformatted expression */
|
||||
w += sprintf(w, "%ld", val);
|
||||
*w = 0;
|
||||
if (exprDebug) printf("simple expression %s\n", s);
|
||||
}
|
||||
else if (*r == ',')
|
||||
{
|
||||
/* single comma */
|
||||
*w++ = *r++;
|
||||
}
|
||||
else {
|
||||
/* unquoted string (i.e plain word) */
|
||||
do {
|
||||
*w++ = *r++;
|
||||
} while (*r && !strchr("%(\"', \t\n", *r));
|
||||
*w = 0;
|
||||
if (exprDebug) printf("plain word '%s'\n", s);
|
||||
}
|
||||
/* copy space */
|
||||
while (isspace((unsigned char)*r)) *w++ = *r++;
|
||||
/* terminate */
|
||||
*w = 0;
|
||||
}
|
||||
return w - buffer;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef expr_h
|
||||
#define expr_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern {
|
||||
#endif
|
||||
|
||||
extern int exprDebug;
|
||||
|
||||
size_t replaceExpressions(const char* source, char* buffer, size_t buffersize);
|
||||
/* Resolve integer expressions that are either free standing
|
||||
* or in parentheses () embedded in an unquoted word.
|
||||
* Do not resolve expressions in single or double quoted strings.
|
||||
* An expression optionally starts with a integer format such as %x.
|
||||
* It consists of integer numbers, operators and parentheses ().
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
+3
-254
@@ -47,193 +47,11 @@ epicsShareFunc int epicsShareAPI iocshCmd(const char *cmd);
|
||||
|
||||
#define IS_ABS_PATH(filename) (filename[0] == OSI_PATH_SEPARATOR[0]) /* may be different for other OS ? */
|
||||
|
||||
#include "expr.h"
|
||||
#include "require.h"
|
||||
|
||||
int runScriptDebug=0;
|
||||
|
||||
static int parseExpr(const char** pp, long* v, int op);
|
||||
|
||||
static int parseValue(const char** pp, long* v)
|
||||
{
|
||||
long val;
|
||||
const char *p = *pp;
|
||||
char o;
|
||||
|
||||
/* A value is optionally prefixed with an unary operator + - ! ~.
|
||||
* It is either a number (decimal, octal or hex)
|
||||
* or an expression in ().
|
||||
* Allowed chars after a number: operators, closing parenthesis, whitespace, quotes, end of string
|
||||
*/
|
||||
|
||||
/* first look for value */
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
o = *p;
|
||||
if (memchr("+-~!", o, 4))
|
||||
{
|
||||
/* handle unary operators */
|
||||
p++;
|
||||
if (!parseValue(&p, &val)) return 0; /* no valid value */
|
||||
if (o == '-') val=-val;
|
||||
else if (o == '~') val=~val;
|
||||
else if (o == '!') val=!val;
|
||||
}
|
||||
else if (o == '(')
|
||||
{
|
||||
/* handle sub-expression */
|
||||
if (runScriptDebug > 1) printf("parseValue: subexpression '%s'\n", p);
|
||||
p++;
|
||||
if (parseExpr(&p, &val, 0) < 0) return 0; /* no valid expression */
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (*p++ != ')') return 0; /* missing ) */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* get number */
|
||||
char* e;
|
||||
val = strtol(p, &e, 0);
|
||||
if (e == p) return 0; /* no number */
|
||||
|
||||
if (isalpha((unsigned char)*p))
|
||||
{
|
||||
/* followed by rubbish */
|
||||
if (runScriptDebug > 1) printf("parseValue: bail out from '%s' at '%s'\n", *pp, e);
|
||||
return 0;
|
||||
}
|
||||
p = e;
|
||||
}
|
||||
if (runScriptDebug > 1) printf("parseValue: '%.*s' = %ld rest '%s'\n", (int)(p-*pp), *pp, val, p);
|
||||
*pp = p;
|
||||
*v = val;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static long ipow(long base, long exp)
|
||||
{
|
||||
long v;
|
||||
if (exp < 0) return 0;
|
||||
if (exp == 0) return 1;
|
||||
v = base;
|
||||
while (--exp) v *= base; /* optimize this! */
|
||||
return v;
|
||||
}
|
||||
|
||||
struct {char str[3]; char pr;} ops[] = {
|
||||
{"",0},
|
||||
{"**",2},
|
||||
{"*", 3},{"/",3},{"%",3},
|
||||
{"+",4},{"-",4},
|
||||
{"<<",5},{">>>",5},{">>",5},
|
||||
{"<=>",6},{"<=",6},{">=",6},{"<",6},{">",6},
|
||||
{"==",7},{"!=",7},
|
||||
{"&&",11},{"||",12},
|
||||
{"&",8},{"^",9},{"|",10}
|
||||
};
|
||||
|
||||
static int startsWith(const char* p, const char* s)
|
||||
{
|
||||
int i = 0;
|
||||
while (*s) { i++; if (*p++ != *s++) return 0; }
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parseOp(const char** pp)
|
||||
{
|
||||
const char *p = *pp;
|
||||
int o, l;
|
||||
|
||||
while (isspace((unsigned char)*p)) p++;
|
||||
if (runScriptDebug > 1) printf("parseOp: check %s\n", p);
|
||||
if (ispunct((unsigned char)*p))
|
||||
{
|
||||
for (o = 1; o < (int)(sizeof(ops)/sizeof(ops[0])); o++)
|
||||
{
|
||||
if ((l = startsWith(p, ops[o].str)))
|
||||
{
|
||||
/* operator found */
|
||||
if (runScriptDebug > 1) printf("parseOp: %.3s\n", ops[0].str);
|
||||
*pp = p+l;
|
||||
return o;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (runScriptDebug > 1) printf("parseOp: end\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parseExpr(const char** pp, long* v, int o)
|
||||
{
|
||||
const char *p = *pp;
|
||||
long val = 0;
|
||||
long val2;
|
||||
int o2 = o;
|
||||
int pr = ops[o].pr;
|
||||
|
||||
if (runScriptDebug > 1) printf("parseExpr: o = %.3s\n", ops[o].str);
|
||||
do {
|
||||
if (!parseValue(&p, &val2)) return -1;
|
||||
if ((o2 = parseOp(&p)) != 0 && ops[o2].pr < pr)
|
||||
if ((o2 = parseExpr(&p, &val2, o2)) < 0) return -1;
|
||||
if (runScriptDebug > 1) printf("parseExpr: %ld %.3s %ld\n", val, ops[o].str, val2);
|
||||
switch(o)
|
||||
{
|
||||
case 0: val = val2; break;
|
||||
case 1: val = ipow(val, val2); break;
|
||||
case 2: val *= val2; break;
|
||||
case 3: val /= val2; break;
|
||||
case 4: val %= val2; break;
|
||||
case 5: val += val2; break;
|
||||
case 6: val -= val2; break;
|
||||
case 7: val <<= val2; break;
|
||||
case 8: val = (unsigned long)val >> val2; break;
|
||||
case 9: val >>= val2; break;
|
||||
case 10: val = val < val2 ? -1 : val == val2 ? 0 : 1; break;
|
||||
case 11: val = val <= val2; break;
|
||||
case 12: val = val >= val2; break;
|
||||
case 13: val = val < val2; break;
|
||||
case 14: val = val > val2; break;
|
||||
case 15: val = val == val2; break;
|
||||
case 16: val = val != val2; break;
|
||||
case 17: val = val && val2; break;
|
||||
case 18: val = val || val2; break;
|
||||
case 19: val &= val2; break;
|
||||
case 20: val ^= val2; break;
|
||||
case 21: val |= val2; break;
|
||||
}
|
||||
o = o2;
|
||||
} while (o && pr <= ops[o].pr);
|
||||
if (runScriptDebug > 1) printf("parseExpr: result %ld\n", val);
|
||||
*pp = p;
|
||||
*v = val;
|
||||
return o;
|
||||
}
|
||||
|
||||
const char* getFormat(const char** pp)
|
||||
{
|
||||
static char format [20];
|
||||
const char* p = *pp;
|
||||
unsigned int i = 1;
|
||||
if (runScriptDebug > 1) printf("getFormat %s\n", p);
|
||||
if ((format[0] = *p++) == '%')
|
||||
{
|
||||
while (i < sizeof(format) && memchr(" #-+0", *p, 5))
|
||||
format[i++] = *p++;
|
||||
while (i < sizeof(format) && *p >= '0' && *p <= '9')
|
||||
format[i++] = *p++;
|
||||
if (i < sizeof(format))
|
||||
format[i++] = 'l';
|
||||
if (i < sizeof(format) && memchr("diouxXc", *p, 7))
|
||||
{
|
||||
format[i++] = *p++;
|
||||
format[i] = 0;
|
||||
*pp = p;
|
||||
if (runScriptDebug > 1) printf("format = '%s'\n", format);
|
||||
return format;
|
||||
}
|
||||
}
|
||||
if (runScriptDebug > 1) printf("no format\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int runScript(const char* filename, const char* args)
|
||||
{
|
||||
MAC_HANDLE *mac = NULL;
|
||||
@@ -384,78 +202,8 @@ int runScript(const char* filename, const char* args)
|
||||
/* find local variable assignments */
|
||||
if ((x = strpbrk(p, "=(, \t\n\r")) != NULL && *x=='=')
|
||||
{
|
||||
const char* r;
|
||||
char* s;
|
||||
char* w;
|
||||
long val;
|
||||
|
||||
*x++ = 0;
|
||||
r = x;
|
||||
w = line_raw;
|
||||
while (*r)
|
||||
{
|
||||
/* Resolve integer expressions that are either free standing
|
||||
* or in parentheses () embedded in an unquoted word.
|
||||
* Do not resolve expressions in single or double quoted strings.
|
||||
* An expression optionally starts with a integer format such as %x.
|
||||
* It consists of integer numbers, operators and parentheses ().
|
||||
*/
|
||||
s = w;
|
||||
if (*r == '"' || *r == '\'')
|
||||
{
|
||||
/* quoted strings */
|
||||
char c = *w++ = *r++;
|
||||
while (*r && *r != c) {
|
||||
if (*r == '\\' && !(*w++ = *r++)) break;
|
||||
*w++ = *r++;
|
||||
}
|
||||
if (*r) *w++ = *r++;
|
||||
*w = 0;
|
||||
if (runScriptDebug > 1) printf("quoted string %s\n", s);
|
||||
}
|
||||
else if (*r == '%')
|
||||
{
|
||||
/* formatted expression */
|
||||
const char* r2 = r;
|
||||
const char* f;
|
||||
if (runScriptDebug > 1) printf("formatted expression after '%s'\n", s);
|
||||
if ((f = getFormat(&r2)) && parseExpr(&r2, &val, 0) == 0)
|
||||
{
|
||||
r = r2;
|
||||
if (*s == '(' && *r2++ == ')')
|
||||
{
|
||||
w = s;
|
||||
r = r2;
|
||||
}
|
||||
w += sprintf(w, f , val);
|
||||
if (runScriptDebug > 1) printf("formatted expression %s\n", s);
|
||||
}
|
||||
}
|
||||
else if (parseExpr(&r, &val, 0) == 0)
|
||||
{
|
||||
/* unformatted expression */
|
||||
w += sprintf(w, "%ld", val);
|
||||
*w = 0;
|
||||
if (runScriptDebug > 1) printf("simple expression %s\n", s);
|
||||
}
|
||||
else if (*r == ',')
|
||||
{
|
||||
/* single comma */
|
||||
*w++ = *r++;
|
||||
}
|
||||
else {
|
||||
/* unquoted string (i.e plain word) */
|
||||
do {
|
||||
*w++ = *r++;
|
||||
} while (*r && !strchr("%(\"', \t\n", *r));
|
||||
*w = 0;
|
||||
if (runScriptDebug > 1) printf("plain word '%s'\n", s);
|
||||
}
|
||||
/* copy space */
|
||||
while (isspace((unsigned char)*r)) *w++ = *r++;
|
||||
/* terminate */
|
||||
*w = 0;
|
||||
}
|
||||
replaceExpressions(x, line_raw, line_raw_size);
|
||||
if (runScriptDebug)
|
||||
printf("runScript: assign %s=%s\n", p, line_raw);
|
||||
macPutValue(mac, p, line_raw);
|
||||
@@ -596,6 +344,7 @@ int afterInit(char* cmd, char* a1, char* a2, char* a3, char* a4, char* a5, char*
|
||||
}
|
||||
|
||||
epicsExportAddress(int, runScriptDebug);
|
||||
epicsExportAddress(int, exprDebug);
|
||||
|
||||
static const iocshFuncDef runScriptDef = {
|
||||
"runScript", 2, (const iocshArg *[]) {
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
registrar(runScriptRegister)
|
||||
variable(runScriptDebug,int)
|
||||
variable(exprDebug,int)
|
||||
|
||||
Reference in New Issue
Block a user