diff options
-rw-r--r-- | NEWS.md | 1 | ||||
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | lr.1 | 1 | ||||
-rw-r--r-- | lr.c | 36 |
4 files changed, 35 insertions, 4 deletions
diff --git a/NEWS.md b/NEWS.md index 8fc633f..5dd0ffe 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,7 @@ ## HEAD * Feature: new option `-B` for breadth first traversal. +* Feature: new syntax `? :` for ternary operator. ## 1.1 (2017-10-29) diff --git a/README.md b/README.md index 3fc6e25..8d59713 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,7 @@ Default: `n`. <expr> ::= <expr> || <expr> -- disjunction | <expr> && <expr> -- conjunction + | <expr> ? <expr> : <expr> -- ternary operator | ! <expr> -- negation | ( <expr ) | <timeprop> <numop> <dur> diff --git a/lr.1 b/lr.1 index 8c13121..a51a95b 100644 --- a/lr.1 +++ b/lr.1 @@ -285,6 +285,7 @@ tests are given by the following EBNF: .Bd -literal <expr> ::= <expr> || <expr> -- disjunction | <expr> && <expr> -- conjunction + | <expr> ? <expr> : <expr> -- ternary operator | ! <expr> -- negation | ( <expr ) | <timeprop> <numop> <dur> diff --git a/lr.c b/lr.c index 5e82a84..f9c1ca5 100644 --- a/lr.c +++ b/lr.c @@ -170,6 +170,7 @@ struct fileinfo { enum op { EXPR_OR = 1, EXPR_AND, + EXPR_COND, EXPR_NOT, EXPR_LT, EXPR_LE, @@ -235,7 +236,7 @@ struct expr { char *string; int64_t num; regex_t *regex; - } a, b; + } a, b, c; }; static char *pos; @@ -407,7 +408,7 @@ parse_op() } static struct expr *parse_cmp(); -static struct expr *parse_or(); +static struct expr *parse_cond(); static struct expr * parse_inner() @@ -434,7 +435,7 @@ parse_inner() not->a.expr = e; return not; } else if (token("(")) { - struct expr *e = parse_or(); + struct expr *e = parse_cond(); if (token(")")) return e; parse_error("missing ) at '%.15s'", pos); @@ -875,10 +876,33 @@ parse_or() } static struct expr * +parse_cond() +{ + struct expr *e1 = parse_or(); + + if (token("?")) { + struct expr *e2 = parse_or(); + if (token(":")) { + struct expr *e3 = parse_cond(); + struct expr *r = mkexpr(EXPR_COND); + r->a.expr = e1; + r->b.expr = e2; + r->c.expr = e3; + + return r; + } else { + parse_error(": expected at '%.15s'", pos); + } + } + + return e1; +} + +static struct expr * parse_expr(const char *s) { pos = (char *)s; - struct expr *e = parse_or(); + struct expr *e = parse_cond(); if (*pos) parse_error("trailing garbage at '%.15s'", pos); return e; @@ -1195,6 +1219,10 @@ eval(struct expr *e, struct fileinfo *fi) return eval(e->a.expr, fi) || eval(e->b.expr, fi); case EXPR_AND: return eval(e->a.expr, fi) && eval(e->b.expr, fi); + case EXPR_COND: + return eval(e->a.expr, fi) + ? eval(e->b.expr, fi) + : eval(e->c.expr, fi); case EXPR_NOT: return !eval(e->a.expr, fi); case EXPR_PRUNE: |