Replace the last use of exceptions (in Expr) with setjmp/longjmp.

Without -fno-exceptions, the branch coverage information is
practically useless, as every call becomes a branch.

The functionality of Expr is retained as-is, although SjLj error
handling is a maintenance nightmare. However, the entire parser
probably should be eventually replaced, so for now it is not
a great concern.
This commit is contained in:
whitequark 2016-07-25 21:46:35 +00:00
parent 65e2cccde0
commit 977a0b8e6d
2 changed files with 34 additions and 15 deletions

View File

@ -616,24 +616,41 @@ static int OperandsP;
static Expr *Operators[MAX_UNPARSED]; static Expr *Operators[MAX_UNPARSED];
static int OperatorsP; static int OperatorsP;
static jmp_buf exprjmp;
static const char *errors[] = {
"operator stack full!",
"operator stack empty (get top)",
"operator stack empty (pop)",
"operand stack full",
"operand stack empty",
"no token to consume",
"end of expression unexpected",
"expected: )",
"expected expression",
"too long",
"unknown name",
"unexpected characters",
};
void Expr::PushOperator(Expr *e) { void Expr::PushOperator(Expr *e) {
if(OperatorsP >= MAX_UNPARSED) throw "operator stack full!"; if(OperatorsP >= MAX_UNPARSED) longjmp(exprjmp, 0);
Operators[OperatorsP++] = e; Operators[OperatorsP++] = e;
} }
Expr *Expr::TopOperator() { Expr *Expr::TopOperator() {
if(OperatorsP <= 0) throw "operator stack empty (get top)"; if(OperatorsP <= 0) longjmp(exprjmp, 1);
return Operators[OperatorsP-1]; return Operators[OperatorsP-1];
} }
Expr *Expr::PopOperator() { Expr *Expr::PopOperator() {
if(OperatorsP <= 0) throw "operator stack empty (pop)"; if(OperatorsP <= 0) longjmp(exprjmp, 2);
return Operators[--OperatorsP]; return Operators[--OperatorsP];
} }
void Expr::PushOperand(Expr *e) { void Expr::PushOperand(Expr *e) {
if(OperandsP >= MAX_UNPARSED) throw "operand stack full"; if(OperandsP >= MAX_UNPARSED) longjmp(exprjmp, 3);
Operands[OperandsP++] = e; Operands[OperandsP++] = e;
} }
Expr *Expr::PopOperand() { Expr *Expr::PopOperand() {
if(OperandsP <= 0) throw "operand stack empty"; if(OperandsP <= 0) longjmp(exprjmp, 4);
return Operands[--OperandsP]; return Operands[--OperandsP];
} }
Expr *Expr::Next() { Expr *Expr::Next() {
@ -641,7 +658,7 @@ Expr *Expr::Next() {
return Unparsed[UnparsedP]; return Unparsed[UnparsedP];
} }
void Expr::Consume() { void Expr::Consume() {
if(UnparsedP >= UnparsedCnt) throw "no token to consume"; if(UnparsedP >= UnparsedCnt) longjmp(exprjmp, 5);
UnparsedP++; UnparsedP++;
} }
@ -706,7 +723,7 @@ void Expr::Parse() {
for(;;) { for(;;) {
Expr *n = Next(); Expr *n = Next();
if(!n) throw "end of expression unexpected"; if(!n) longjmp(exprjmp, 6);
if(n->op == Op::CONSTANT) { if(n->op == Op::CONSTANT) {
PushOperand(n); PushOperand(n);
@ -715,7 +732,7 @@ void Expr::Parse() {
Consume(); Consume();
Parse(); Parse();
n = Next(); n = Next();
if(n->op != Op::PAREN || n->c != ')') throw "expected: )"; if(n->op != Op::PAREN || n->c != ')') longjmp(exprjmp, 7);
Consume(); Consume();
} else if(n->op == Op::UNARY_OP) { } else if(n->op == Op::UNARY_OP) {
PushOperator(n); PushOperator(n);
@ -730,7 +747,7 @@ void Expr::Parse() {
Consume(); Consume();
continue; continue;
} else { } else {
throw "expected expression"; longjmp(exprjmp, 8);
} }
n = Next(); n = Next();
@ -750,7 +767,7 @@ void Expr::Parse() {
void Expr::Lex(const char *in) { void Expr::Lex(const char *in) {
while(*in) { while(*in) {
if(UnparsedCnt >= MAX_UNPARSED) throw "too long"; if(UnparsedCnt >= MAX_UNPARSED) longjmp(exprjmp, 9);
char c = *in; char c = *in;
if(isdigit(c) || c == '.') { if(isdigit(c) || c == '.') {
@ -789,7 +806,7 @@ void Expr::Lex(const char *in) {
e->op = Op::CONSTANT; e->op = Op::CONSTANT;
e->v = PI; e->v = PI;
} else { } else {
throw "unknown name"; longjmp(exprjmp, 10);
} }
Unparsed[UnparsedCnt++] = e; Unparsed[UnparsedCnt++] = e;
} else if(strchr("+-*/()", c)) { } else if(strchr("+-*/()", c)) {
@ -803,7 +820,7 @@ void Expr::Lex(const char *in) {
in++; in++;
} else { } else {
// This is a lex error. // This is a lex error.
throw "unexpected characters"; longjmp(exprjmp, 11);
} }
} }
} }
@ -815,12 +832,13 @@ Expr *Expr::From(const char *in, bool popUpError) {
OperatorsP = 0; OperatorsP = 0;
Expr *r; Expr *r;
try { int erridx = setjmp(exprjmp);
if(!erridx) {
Lex(in); Lex(in);
Parse(); Parse();
r = PopOperand(); r = PopOperand();
} catch (const char *e) { } else {
dbp("exception: parse/lex error: %s", e); dbp("exception: parse/lex error: %s", errors[erridx]);
if(popUpError) { if(popUpError) {
Error("Not a valid number or expression: '%s'", in); Error("Not a valid number or expression: '%s'", in);
} }

View File

@ -15,6 +15,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdarg.h> #include <stdarg.h>
#include <math.h> #include <math.h>
#include <setjmp.h>
#include <limits.h> #include <limits.h>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>