aboutsummaryrefslogtreecommitdiff
path: root/Src/ns-eel2/nseel-eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/ns-eel2/nseel-eval.c')
-rw-r--r--Src/ns-eel2/nseel-eval.c447
1 files changed, 447 insertions, 0 deletions
diff --git a/Src/ns-eel2/nseel-eval.c b/Src/ns-eel2/nseel-eval.c
new file mode 100644
index 00000000..f4f6136c
--- /dev/null
+++ b/Src/ns-eel2/nseel-eval.c
@@ -0,0 +1,447 @@
+/*
+ Expression Evaluator Library (NS-EEL) v2
+ Copyright (C) 2004-2013 Cockos Incorporated
+ Copyright (C) 1999-2003 Nullsoft, Inc.
+
+ nseel-eval.c
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <string.h>
+#include <ctype.h>
+#include "ns-eel-int.h"
+#include "wdlcstring.h"
+
+
+static const char *nseel_skip_space_and_comments(const char *p, const char *endptr)
+{
+ for (;;)
+ {
+ while (p < endptr && isspace(p[0])) p++;
+ if (p >= endptr-1 || *p != '/') return p;
+
+ if (p[1]=='/')
+ {
+ while (p < endptr && *p != '\r' && *p != '\n') p++;
+ }
+ else if (p[1] == '*')
+ {
+ p+=2;
+ while (p < endptr-1 && (p[0] != '*' || p[1] != '/')) p++;
+ p+=2;
+ if (p>=endptr) return endptr;
+ }
+ else return p;
+ }
+}
+
+// removes any escaped characters, also will convert pairs delim_char into single delim_chars
+int nseel_filter_escaped_string(char *outbuf, int outbuf_sz, const char *rdptr, size_t rdptr_size, char delim_char)
+{
+ int outpos = 0;
+ const char *rdptr_end = rdptr + rdptr_size;
+ while (rdptr < rdptr_end && outpos < outbuf_sz-1)
+ {
+ char thisc=*rdptr;
+ if (thisc == '\\' && rdptr < rdptr_end-1)
+ {
+ const char nc = rdptr[1];
+ if (nc == 'r' || nc == 'R') { thisc = '\r'; }
+ else if (nc == 'n' || nc == 'N') { thisc = '\n'; }
+ else if (nc == 't' || nc == 'T') { thisc = '\t'; }
+ else if (nc == 'b' || nc == 'B') { thisc = '\b'; }
+ else if ((nc >= '0' && nc <= '9') || nc == 'x' || nc == 'X')
+ {
+ unsigned char c=0;
+ char base_shift = 3;
+ char num_top = '7';
+
+ rdptr++; // skip backslash
+ if (nc > '9') // implies xX
+ {
+ base_shift = 4;
+ num_top = '9';
+ rdptr ++; // skip x
+ }
+
+ while (rdptr < rdptr_end)
+ {
+ char tc=*rdptr;
+ if (tc >= '0' && tc <= num_top)
+ {
+ c = (c<<base_shift) + tc - '0';
+ }
+ else if (base_shift==4)
+ {
+ if (tc >= 'a' && tc <= 'f')
+ {
+ c = (c<<base_shift) + (tc - 'a' + 10);
+ }
+ else if (tc >= 'A' && tc <= 'F')
+ {
+ c = (c<<base_shift) + (tc - 'A' + 10);
+ }
+ else break;
+ }
+ else break;
+
+ rdptr++;
+ }
+ outbuf[outpos++] = (char)c;
+ continue;
+ }
+ else // \c where c is an unknown character drops the backslash -- works for \, ', ", etc
+ {
+ thisc = nc;
+ }
+ rdptr+=2;
+ }
+ else
+ {
+ if (thisc == delim_char) break;
+ rdptr++;
+ }
+ outbuf[outpos++] = thisc;
+ }
+ outbuf[outpos]=0;
+ return outpos;
+}
+
+int nseel_stringsegments_tobuf(char *bufOut, int bufout_sz, struct eelStringSegmentRec *list) // call with NULL to calculate size, or non-null to generate to buffer (returning size used)
+{
+ int pos=0;
+ while (list)
+ {
+ if (!bufOut)
+ {
+ pos += list->str_len;
+ }
+ else if (list->str_len > 1)
+ {
+ if (pos >= bufout_sz) break;
+ pos += nseel_filter_escaped_string(bufOut + pos, bufout_sz-pos, list->str_start+1, list->str_len-1, list->str_start[0]);
+ }
+ list = list->_next;
+ }
+ return pos;
+}
+
+
+
+// state can be NULL, it will be set if finished with unterminated thing: 1 for multiline comment, ' or " for string
+const char *nseel_simple_tokenizer(const char **ptr, const char *endptr, int *lenOut, int *state)
+{
+ const char *p = *ptr;
+ const char *rv = p;
+
+ if (state) // if state set, returns comments as tokens
+ {
+ if (*state == 1) goto in_comment;
+
+ #ifndef NSEEL_EEL1_COMPAT_MODE
+ if (*state == '\'' || *state == '\"')
+ {
+ delim = (char)*state;
+ goto in_string;
+ }
+ #endif
+
+ // skip any whitespace
+ while (p < endptr && isspace(p[0])) p++;
+ }
+ else
+ {
+ // state not passed, skip comments (do not return them as tokens)
+ p = nseel_skip_space_and_comments(p,endptr);
+ }
+
+ if (p >= endptr)
+ {
+ *ptr = endptr;
+ *lenOut = 0;
+ return NULL;
+ }
+
+ rv=p;
+
+ if (*p == '$' && p+3 < endptr && p[1] == '\'' && p[3] == '\'')
+ {
+ p+=4;
+ }
+ else if (state && *p == '/' && p < endptr-1 && (p[1] == '/' || p[1] == '*'))
+ {
+ if (p[1] == '/')
+ {
+ while (p < endptr && *p != '\r' && *p != '\n') p++; // advance to end of line
+ }
+ else
+ {
+ if (state) *state=1;
+ p+=2;
+in_comment:
+ while (p < endptr)
+ {
+ const char c = *p++;
+ if (c == '*' && p < endptr && *p == '/')
+ {
+ p++;
+ if (state) *state=0;
+ break;
+ }
+ }
+
+ }
+ }
+ else if (isalnum(*p) || *p == '_' || *p == '#' || *p == '$')
+ {
+ if (*p == '$' && p < endptr-1 && p[1] == '~') p++;
+ p++;
+ while (p < endptr && (isalnum(*p) || *p == '_' || *p == '.')) p++;
+ }
+#ifndef NSEEL_EEL1_COMPAT_MODE
+ else if (*p == '\'' || *p == '\"')
+ {
+ delim = *p++;
+ if (state) *state=delim;
+in_string:
+
+ while (p < endptr)
+ {
+ const char c = *p++;
+ if (p < endptr && c == '\\') p++; // skip escaped characters
+ else if (c == delim)
+ {
+ if (state) *state=0;
+ break;
+ }
+ }
+ }
+#endif
+ else
+ {
+ p++;
+ }
+ *ptr = p;
+ *lenOut = (int) (p - rv);
+ return p>rv ? rv : NULL;
+}
+
+
+
+#ifdef NSEEL_SUPER_MINIMAL_LEXER
+
+ int nseellex(opcodeRec **output, YYLTYPE * yylloc_param, compileContext *scctx)
+ {
+ int rv=0,toklen=0;
+ const char *rdptr = scctx->rdbuf;
+ const char *endptr = scctx->rdbuf_end;
+ const char *tok = nseel_simple_tokenizer(&rdptr,endptr,&toklen,NULL);
+ *output = 0;
+ if (tok)
+ {
+ rv = tok[0];
+ if (rv == '$')
+ {
+ if (rdptr != tok+1)
+ {
+ *output = nseel_translate(scctx,tok,rdptr-tok);
+ if (*output) rv=VALUE;
+ }
+ }
+#ifndef NSEEL_EEL1_COMPAT_MODE
+ else if (rv == '#' && scctx->onNamedString)
+ {
+ *output = nseel_translate(scctx,tok,rdptr-tok);
+ if (*output) rv=STRING_IDENTIFIER;
+ }
+ else if (rv == '\'')
+ {
+ if (toklen > 1 && tok[toklen-1] == '\'')
+ {
+ *output = nseel_translate(scctx, tok, toklen);
+ if (*output) rv = VALUE;
+ }
+ else scctx->gotEndOfInput|=8;
+ }
+ else if (rv == '\"' && scctx->onString)
+ {
+ if (toklen > 1 && tok[toklen-1] == '\"')
+ {
+ *output = (opcodeRec *)nseel_createStringSegmentRec(scctx,tok,toklen);
+ if (*output) rv = STRING_LITERAL;
+ }
+ else scctx->gotEndOfInput|=16;
+ }
+#endif
+ else if (isalpha(rv) || rv == '_')
+ {
+ // toklen already valid
+ char buf[NSEEL_MAX_VARIABLE_NAMELEN*2];
+ if (toklen > sizeof(buf) - 1) toklen=sizeof(buf) - 1;
+ memcpy(buf,tok,toklen);
+ buf[toklen]=0;
+ *output = nseel_createCompiledValuePtr(scctx, NULL, buf);
+ if (*output) rv = IDENTIFIER;
+ }
+ else if ((rv >= '0' && rv <= '9') || (rv == '.' && (rdptr < endptr && rdptr[0] >= '0' && rdptr[0] <= '9')))
+ {
+ if (rv == '0' && rdptr < endptr && (rdptr[0] == 'x' || rdptr[0] == 'X'))
+ {
+ rdptr++;
+ while (rdptr < endptr && (rv=rdptr[0]) && ((rv>='0' && rv<='9') || (rv>='a' && rv<='f') || (rv>='A' && rv<='F'))) rdptr++;
+ }
+ else
+ {
+ int pcnt=rv == '.';
+ while (rdptr < endptr && (rv=rdptr[0]) && ((rv>='0' && rv<='9') || (rv == '.' && !pcnt++))) rdptr++;
+ }
+ *output = nseel_translate(scctx,tok,rdptr-tok);
+ if (*output) rv=VALUE;
+ }
+ else if (rv == '<')
+ {
+ const char nc=*rdptr;
+ if (nc == '<')
+ {
+ rdptr++;
+ rv=TOKEN_SHL;
+ }
+ else if (nc == '=')
+ {
+ rdptr++;
+ rv=TOKEN_LTE;
+ }
+ }
+ else if (rv == '>')
+ {
+ const char nc=*rdptr;
+ if (nc == '>')
+ {
+ rdptr++;
+ rv=TOKEN_SHR;
+ }
+ else if (nc == '=')
+ {
+ rdptr++;
+ rv=TOKEN_GTE;
+ }
+ }
+ else if (rv == '&' && *rdptr == '&')
+ {
+ rdptr++;
+ rv = TOKEN_LOGICAL_AND;
+ }
+ else if (rv == '|' && *rdptr == '|')
+ {
+ rdptr++;
+ rv = TOKEN_LOGICAL_OR;
+ }
+ else if (*rdptr == '=')
+ {
+ switch (rv)
+ {
+ case '+': rv=TOKEN_ADD_OP; rdptr++; break;
+ case '-': rv=TOKEN_SUB_OP; rdptr++; break;
+ case '%': rv=TOKEN_MOD_OP; rdptr++; break;
+ case '|': rv=TOKEN_OR_OP; rdptr++; break;
+ case '&': rv=TOKEN_AND_OP; rdptr++; break;
+ case '~': rv=TOKEN_XOR_OP; rdptr++; break;
+ case '/': rv=TOKEN_DIV_OP; rdptr++; break;
+ case '*': rv=TOKEN_MUL_OP; rdptr++; break;
+ case '^': rv=TOKEN_POW_OP; rdptr++; break;
+ case '!':
+ rdptr++;
+ if (rdptr < endptr && *rdptr == '=')
+ {
+ rdptr++;
+ rv=TOKEN_NE_EXACT;
+ }
+ else
+ rv=TOKEN_NE;
+ break;
+ case '=':
+ rdptr++;
+ if (rdptr < endptr && *rdptr == '=')
+ {
+ rdptr++;
+ rv=TOKEN_EQ_EXACT;
+ }
+ else
+ rv=TOKEN_EQ;
+ break;
+ }
+ }
+ }
+
+ scctx->rdbuf = rdptr;
+ yylloc_param->first_column = (int)(tok - scctx->rdbuf_start);
+ return rv;
+ }
+
+
+ void nseelerror(YYLTYPE *pos,compileContext *ctx, const char *str)
+ {
+ ctx->errVar=pos->first_column>0?pos->first_column:(int)(ctx->rdbuf_end - ctx->rdbuf_start);
+ }
+
+
+#else
+
+ int nseel_gets(compileContext *ctx, char *buf, size_t sz)
+ {
+ int n=0;
+ const char *endptr = ctx->rdbuf_end;
+ const char *rdptr = ctx->rdbuf;
+ if (!rdptr) return 0;
+
+ while (n < sz && rdptr < endptr) buf[n++] = *rdptr++;
+ ctx->rdbuf=rdptr;
+ return n;
+
+ }
+
+
+ //#define EEL_TRACE_LEX
+
+ #ifdef EEL_TRACE_LEX
+ #define nseellex nseellex2
+
+ #endif
+ #include "lex.nseel.c"
+
+ #ifdef EEL_TRACE_LEX
+
+ #undef nseellex
+
+ int nseellex(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner)
+ {
+ int a=nseellex2(yylval_param,yylloc_param,yyscanner);
+
+ char buf[512];
+ sprintf(buf,"tok: %c (%d)\n",a,a);
+ OutputDebugString(buf);
+ return a;
+ }
+ #endif//EEL_TRACE_LEX
+
+
+ void nseelerror(YYLTYPE *pos,compileContext *ctx, const char *str)
+ {
+ ctx->errVar=pos->first_column>0?pos->first_column:(int)(ctx->rdbuf_end - ctx->rdbuf_start);
+ }
+#endif // !NSEEL_SUPER_MINIMAL_LEXER