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:
parent
65e2cccde0
commit
977a0b8e6d
48
src/expr.cpp
48
src/expr.cpp
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user