求教C++高手一个编写逻辑运算符分析算法的问题
最近有一个项目需要自定义一种脚本语言,脚本语言中可能包含&& || () 等逻辑运算符。
现在需要编写一个算法来parse脚本语言,通过包含的逻辑运算符决定脚本的执行顺序。
比如说有脚本如下
press:OK||(press:Yes&&Key:A)
press:Back
其中press:OK press:Yes Key:A等的执行结果均为布尔值。
像这样的算法应该怎样编写才比较合理呢。尝试写了几种,总是会出现一些没考虑到的情况。
小弟在这方面经验不足,还请大拿指点一下。
谢谢。
[解决办法]
* *//* This program evaluates expressions. Each token (operator, operand, * parenthesis) of the expression must be a seperate argument. The * parser used is a reasonably general one, though any incarnation of * it is language-specific. It is especially nice for expressions. * * No parse tree is needed; a new node is evaluated immediately. * One function can handle multiple operators all of equal precedence, * provided they all associate ((x op x) op x). *//* no getopt needed */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <regex.h>#include <sys/types.h>#include "busybox.h"/* The kinds of value we can have. */enum valtype { integer, string};typedef enum valtype TYPE;/* A value is.... */struct valinfo { TYPE type; /* Which kind. */ union { /* The value itself. */ int i; char *s; } u;};typedef struct valinfo VALUE;/* The arguments given to the program, minus the program name. */static char **args;static VALUE *docolon (VALUE *sv, VALUE *pv);static VALUE *eval (void);static VALUE *int_value (int i);static VALUE *str_value (char *s);static int nextarg (char *str);static int null (VALUE *v);static int toarith (VALUE *v);static void freev (VALUE *v);static void tostring (VALUE *v);int expr_main (int argc, char **argv){ VALUE *v; if (argc == 1) { error_msg_and_die("too few arguments"); } args = argv + 1; v = eval (); if (*args) error_msg_and_die ("syntax error"); if (v->type == integer) printf ("%d\n", v->u.i); else puts (v->u.s); exit (null (v));}/* Return a VALUE for I. */static VALUE *int_value (int i){ VALUE *v; v = xmalloc (sizeof(VALUE)); v->type = integer; v->u.i = i; return v;}/* Return a VALUE for S. */static VALUE *str_value (char *s){ VALUE *v; v = xmalloc (sizeof(VALUE)); v->type = string; v->u.s = strdup (s); return v;}/* Free VALUE V, including structure components. */static void freev (VALUE *v){ if (v->type == string) free (v->u.s); free (v);}/* Return nonzero if V is a null-string or zero-number. */static int null (VALUE *v){ switch (v->type) { case integer: return v->u.i == 0; case string: return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0; default: abort (); }}/* Coerce V to a string value (can't fail). */static void tostring (VALUE *v){ char *temp; if (v->type == integer) { temp = xmalloc (4 * (sizeof (int) / sizeof (char))); sprintf (temp, "%d", v->u.i); v->u.s = temp; v->type = string; }}/* Coerce V to an integer value. Return 1 on success, 0 on failure. */static int toarith (VALUE *v){ int i; switch (v->type) { case integer: return 1; case string: i = 0; /* Don't interpret the empty string as an integer. */ if (v->u.s == 0) return 0; i = atoi(v->u.s); free (v->u.s); v->u.i = i; v->type = integer; return 1; default: abort (); }}/* Return nonzero if the next token matches STR exactly. STR must not be NULL. */static intnextarg (char *str){ if (*args == NULL) return 0; return strcmp (*args, str) == 0;}/* The comparison operator handling functions. */#define cmpf(name, rel) \static int name (l, r) VALUE *l; VALUE *r; \{ \ if (l->type == string || r->type == string) { \ tostring (l); \ tostring (r); \ return strcmp (l->u.s, r->u.s) rel 0; \ } \ else \ return l->u.i rel r->u.i; \} cmpf (less_than, <) cmpf (less_equal, <=) cmpf (equal, ==) cmpf (not_equal, !=) cmpf (greater_equal, >=) cmpf (greater_than, >)#undef cmpf/* The arithmetic operator handling functions. */#define arithf(name, op) \static \int name (l, r) VALUE *l; VALUE *r; \{ \ if (!toarith (l) || !toarith (r)) \ error_msg_and_die ("non-numeric argument"); \ return l->u.i op r->u.i; \}#define arithdivf(name, op) \static int name (l, r) VALUE *l; VALUE *r; \{ \ if (!toarith (l) || !toarith (r)) \ error_msg_and_die ( "non-numeric argument"); \ if (r->u.i == 0) \ error_msg_and_die ( "division by zero"); \ return l->u.i op r->u.i; \} arithf (plus, +) arithf (minus, -) arithf (multiply, *) arithdivf (divide, /) arithdivf (mod, %)#undef arithf#undef arithdivf/* Do the : operator. SV is the VALUE for the lhs (the string), PV is the VALUE for the rhs (the pattern). */static VALUE *docolon (VALUE *sv, VALUE *pv){ VALUE *v; const char *errmsg; struct re_pattern_buffer re_buffer; struct re_registers re_regs; int len; tostring (sv); tostring (pv); if (pv->u.s[0] == '^') { fprintf (stderr, "\warning: unportable BRE: `%s': using `^' as the first character\n\of a basic regular expression is not portable; it is being ignored", pv->u.s); } len = strlen (pv->u.s); memset (&re_buffer, 0, sizeof (re_buffer)); memset (&re_regs, 0, sizeof (re_regs)); re_buffer.allocated = 2 * len; re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated); re_buffer.translate = 0; re_syntax_options = RE_SYNTAX_POSIX_BASIC; errmsg = re_compile_pattern (pv->u.s, len, &re_buffer); if (errmsg) { error_msg_and_die("%s", errmsg); } len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs); if (len >= 0) { /* Were \(...\) used? */ if (re_buffer.re_nsub > 0) { /* was (re_regs.start[1] >= 0) */ sv->u.s[re_regs.end[1]] = '\0'; v = str_value (sv->u.s + re_regs.start[1]); } else v = int_value (len); } else { /* Match failed -- return the right kind of null. */ if (re_buffer.re_nsub > 0) v = str_value (""); else v = int_value (0); } free (re_buffer.buffer); return v;}/* Handle bare operands and ( expr ) syntax. */static VALUE *eval7 (void){ VALUE *v; if (!*args) error_msg_and_die ( "syntax error"); if (nextarg ("(")) { args++; v = eval (); if (!nextarg (")")) error_msg_and_die ( "syntax error"); args++; return v; } if (nextarg (")")) error_msg_and_die ( "syntax error"); return str_value (*args++);}/* Handle match, substr, index, length, and quote keywords. */static VALUE *eval6 (void){ VALUE *l, *r, *v, *i1, *i2; if (nextarg ("quote")) { args++; if (!*args) error_msg_and_die ( "syntax error"); return str_value (*args++); } else if (nextarg ("length")) { args++; r = eval6 (); tostring (r); v = int_value (strlen (r->u.s)); freev (r); return v; } else if (nextarg ("match")) { args++; l = eval6 (); r = eval6 (); v = docolon (l, r); freev (l); freev (r); return v; } else if (nextarg ("index")) { args++; l = eval6 (); r = eval6 (); tostring (l); tostring (r); v = int_value (strcspn (l->u.s, r->u.s) + 1); if (v->u.i == (int) strlen (l->u.s) + 1) v->u.i = 0; freev (l); freev (r); return v; } else if (nextarg ("substr")) { args++; l = eval6 (); i1 = eval6 (); i2 = eval6 (); tostring (l); if (!toarith (i1) || !toarith (i2) || i1->u.i > (int) strlen (l->u.s) || i1->u.i <= 0 || i2->u.i <= 0) v = str_value (""); else { v = xmalloc (sizeof(VALUE)); v->type = string; v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1), l->u.s + i1->u.i - 1, i2->u.i); v->u.s[i2->u.i] = 0; } freev (l); freev (i1); freev (i2); return v; } else return eval7 ();}/* Handle : operator (pattern matching). Calls docolon to do the real work. */static VALUE *eval5 (void){ VALUE *l, *r, *v; l = eval6 (); while (nextarg (":")) { args++; r = eval6 (); v = docolon (l, r); freev (l); freev (r); l = v; } return l;}/* Handle *, /, % operators. */static VALUE *eval4 (void){ VALUE *l, *r; int (*fxn) (), val; l = eval5 (); while (1) { if (nextarg ("*")) fxn = multiply; else if (nextarg ("/")) fxn = divide; else if (nextarg ("%")) fxn = mod; else return l; args++; r = eval5 (); val = (*fxn) (l, r); freev (l); freev (r); l = int_value (val); }}/* Handle +, - operators. */static VALUE *eval3 (void){ VALUE *l, *r; int (*fxn) (), val; l = eval4 (); while (1) { if (nextarg ("+")) fxn = plus; else if (nextarg ("-")) fxn = minus; else return l; args++; r = eval4 (); val = (*fxn) (l, r); freev (l); freev (r); l = int_value (val); }}/* Handle comparisons. */static VALUE *eval2 (void){ VALUE *l, *r; int (*fxn) (), val; l = eval3 (); while (1) { if (nextarg ("<")) fxn = less_than; else if (nextarg ("<=")) fxn = less_equal; else if (nextarg ("=") || nextarg ("==")) fxn = equal; else if (nextarg ("!=")) fxn = not_equal; else if (nextarg (">=")) fxn = greater_equal; else if (nextarg (">")) fxn = greater_than; else return l; args++; r = eval3 (); toarith (l); toarith (r); val = (*fxn) (l, r); freev (l); freev (r); l = int_value (val); }}/* Handle &. */static VALUE *eval1 (void){ VALUE *l, *r; l = eval2 (); while (nextarg ("&")) { args++; r = eval2 (); if (null (l) || null (r)) { freev (l); freev (r); l = int_value (0); } else freev (r); } return l;}/* Handle |. */static VALUE *eval (void){ VALUE *l, *r; l = eval1 (); while (nextarg ("|")) { args++; r = eval1 (); if (null (l)) { freev (l); l = r; } else freev (r); } return l;}