vendor/bc: update to version 5.1.1
This update fixes a parser issue, which in special situations could reject syntactically correct if statements.
This commit is contained in:
parent
5d58a51571
commit
6f49f5cdde
8
NEWS.md
8
NEWS.md
@ -1,5 +1,13 @@
|
|||||||
# News
|
# News
|
||||||
|
|
||||||
|
## 5.1.1
|
||||||
|
|
||||||
|
This is a production release that completes a bug fix from `5.1.0`. The bug
|
||||||
|
exists in all versions of `bc`.
|
||||||
|
|
||||||
|
The bug was that `if` statements without `else` statements would not be handled
|
||||||
|
correctly at the end of files or right before a function definition.
|
||||||
|
|
||||||
## 5.1.0
|
## 5.1.0
|
||||||
|
|
||||||
This is a production release with some fixes and new features.
|
This is a production release with some fixes and new features.
|
||||||
|
@ -396,6 +396,15 @@ void bc_parse_expr(BcParse *p, uint8_t flags);
|
|||||||
*/
|
*/
|
||||||
void bc_parse_parse(BcParse *p);
|
void bc_parse_parse(BcParse *p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ends a series of if statements. This is to ensure that full parses happen
|
||||||
|
* when a file finishes or before defining a function. Without this, bc thinks
|
||||||
|
* that it cannot parse any further. But if we reach the end of a file or a
|
||||||
|
* function definition, we know we can add an empty else clause.
|
||||||
|
* @param p The parser.
|
||||||
|
*/
|
||||||
|
void bc_parse_endif(BcParse *p);
|
||||||
|
|
||||||
/// References to the signal message and its length.
|
/// References to the signal message and its length.
|
||||||
extern const char bc_sig_msg[];
|
extern const char bc_sig_msg[];
|
||||||
extern const uchar bc_sig_msg_len;
|
extern const uchar bc_sig_msg_len;
|
||||||
|
@ -37,6 +37,6 @@
|
|||||||
#define BC_VERSION_H
|
#define BC_VERSION_H
|
||||||
|
|
||||||
/// The current version.
|
/// The current version.
|
||||||
#define VERSION 5.1.0
|
#define VERSION 5.1.1
|
||||||
|
|
||||||
#endif // BC_VERSION_H
|
#endif // BC_VERSION_H
|
||||||
|
@ -65,7 +65,7 @@ with Visual Studio*.
|
|||||||
To build `bc`, run the following from the root directory:
|
To build `bc`, run the following from the root directory:
|
||||||
|
|
||||||
```
|
```
|
||||||
msbuild -property:Configuration=<config> bc.sln
|
msbuild -property:Configuration=<config> vs/bc.sln
|
||||||
```
|
```
|
||||||
|
|
||||||
where `<config>` is either one of `Debug` or `Release`.
|
where `<config>` is either one of `Debug` or `Release`.
|
||||||
@ -73,10 +73,10 @@ where `<config>` is either one of `Debug` or `Release`.
|
|||||||
To build the library, run the following from the root directory:
|
To build the library, run the following from the root directory:
|
||||||
|
|
||||||
```
|
```
|
||||||
msbuild -property:Configuration=<config> bcl.sln
|
msbuild -property:Configuration=<config> vs/bcl.sln
|
||||||
```
|
```
|
||||||
|
|
||||||
where `<config>` is either one of `Debug` or `Release`.
|
where `<config>` is either one of `Debug`, `ReleaseMD`, or `ReleaseMT`.
|
||||||
|
|
||||||
## POSIX-Compatible Systems
|
## POSIX-Compatible Systems
|
||||||
|
|
||||||
|
@ -999,6 +999,44 @@ static void bc_parse_startBody(BcParse *p, uint16_t flags) {
|
|||||||
bc_vec_push(&p->flags, &flags);
|
bc_vec_push(&p->flags, &flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bc_parse_endif(BcParse *p) {
|
||||||
|
|
||||||
|
size_t i;
|
||||||
|
bool good;
|
||||||
|
|
||||||
|
// Not a problem if this is true.
|
||||||
|
if (BC_NO_ERR(!BC_PARSE_NO_EXEC(p))) return;
|
||||||
|
|
||||||
|
good = true;
|
||||||
|
|
||||||
|
// Find an instance of a body that needs closing, i.e., a statement that did
|
||||||
|
// not have a right brace when it should have.
|
||||||
|
for (i = 0; good && i < p->flags.len; ++i) {
|
||||||
|
uint16_t flag = *((uint16_t*) bc_vec_item(&p->flags, i));
|
||||||
|
good = ((flag & BC_PARSE_FLAG_BRACE) != BC_PARSE_FLAG_BRACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we did not find such an instance...
|
||||||
|
if (good) {
|
||||||
|
|
||||||
|
// We set this to restore it later. We don't want the parser thinking
|
||||||
|
// that we are on stdin for this one because it will want more.
|
||||||
|
bool is_stdin = vm.is_stdin;
|
||||||
|
|
||||||
|
vm.is_stdin = false;
|
||||||
|
|
||||||
|
// End all of the if statements and loops.
|
||||||
|
while (p->flags.len > 1 || BC_PARSE_IF_END(p)) {
|
||||||
|
if (BC_PARSE_IF_END(p)) bc_parse_noElse(p);
|
||||||
|
if (p->flags.len > 1) bc_parse_endBody(p, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.is_stdin = is_stdin;
|
||||||
|
}
|
||||||
|
// If we reach here, a block was not properly closed, and we should error.
|
||||||
|
else bc_parse_err(&vm.prs, BC_ERR_PARSE_BLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses an if statement.
|
* Parses an if statement.
|
||||||
* @param p The parser.
|
* @param p The parser.
|
||||||
@ -1730,12 +1768,9 @@ void bc_parse_parse(BcParse *p) {
|
|||||||
// Functions need special parsing.
|
// Functions need special parsing.
|
||||||
else if (p->l.t == BC_LEX_KW_DEFINE) {
|
else if (p->l.t == BC_LEX_KW_DEFINE) {
|
||||||
if (BC_ERR(BC_PARSE_NO_EXEC(p))) {
|
if (BC_ERR(BC_PARSE_NO_EXEC(p))) {
|
||||||
if (p->flags.len == 1 &&
|
bc_parse_endif(p);
|
||||||
BC_PARSE_TOP_FLAG(p) == BC_PARSE_FLAG_IF_END)
|
if (BC_ERR(BC_PARSE_NO_EXEC(p)))
|
||||||
{
|
bc_parse_err(p, BC_ERR_PARSE_TOKEN);
|
||||||
bc_parse_noElse(p);
|
|
||||||
}
|
|
||||||
else bc_parse_err(p, BC_ERR_PARSE_TOKEN);
|
|
||||||
}
|
}
|
||||||
bc_parse_func(p);
|
bc_parse_func(p);
|
||||||
}
|
}
|
||||||
|
43
src/vm.c
43
src/vm.c
@ -839,45 +839,14 @@ static void bc_vm_process(const char *text, bool is_stdin) {
|
|||||||
#if BC_ENABLED
|
#if BC_ENABLED
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ends an if statement that ends a file. This is to ensure that full parses
|
* Ends a series of if statements. This is to ensure that full parses happen
|
||||||
* happen when a file finishes. Without this, bc thinks that it cannot parse
|
* when a file finishes or stdin has no more data. Without this, bc thinks that
|
||||||
* any further. But if we reach the end of a file, we know we can add an empty
|
* it cannot parse any further. But if we reach the end of a file or stdin has
|
||||||
* else clause.
|
* no more data, we know we can add an empty else clause.
|
||||||
*/
|
*/
|
||||||
static void bc_vm_endif(void) {
|
static void bc_vm_endif(void) {
|
||||||
|
bc_parse_endif(&vm.prs);
|
||||||
size_t i;
|
bc_program_exec(&vm.prog);
|
||||||
bool good;
|
|
||||||
|
|
||||||
// Not a problem if this is true.
|
|
||||||
if (BC_NO_ERR(!BC_PARSE_NO_EXEC(&vm.prs))) return;
|
|
||||||
|
|
||||||
good = true;
|
|
||||||
|
|
||||||
// Find an instance of a body that needs closing, i.e., a statement that did
|
|
||||||
// not have a right brace when it should have.
|
|
||||||
for (i = 0; good && i < vm.prs.flags.len; ++i) {
|
|
||||||
uint16_t flag = *((uint16_t*) bc_vec_item(&vm.prs.flags, i));
|
|
||||||
good = ((flag & BC_PARSE_FLAG_BRACE) != BC_PARSE_FLAG_BRACE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we did not find such an instance...
|
|
||||||
if (good) {
|
|
||||||
|
|
||||||
// We set this to restore it later. We don't want the parser thinking
|
|
||||||
// that we are on stdin for this one because it will want more.
|
|
||||||
bool is_stdin = vm.is_stdin;
|
|
||||||
|
|
||||||
vm.is_stdin = false;
|
|
||||||
|
|
||||||
// Cheat and keep parsing empty else clauses until all of them are
|
|
||||||
// satisfied.
|
|
||||||
while (BC_PARSE_IF_END(&vm.prs)) bc_vm_process("else {}", false);
|
|
||||||
|
|
||||||
vm.is_stdin = is_stdin;
|
|
||||||
}
|
|
||||||
// If we reach here, a block was not properly closed, and we should error.
|
|
||||||
else bc_parse_err(&vm.prs, BC_ERR_PARSE_BLOCK);
|
|
||||||
}
|
}
|
||||||
#endif // BC_ENABLED
|
#endif // BC_ENABLED
|
||||||
|
|
||||||
|
@ -14,3 +14,5 @@ rand.bc
|
|||||||
references.bc
|
references.bc
|
||||||
screen.bc
|
screen.bc
|
||||||
strings2.bc
|
strings2.bc
|
||||||
|
ifs.bc
|
||||||
|
ifs2.bc
|
||||||
|
49
tests/bc/scripts/ifs.bc
Normal file
49
tests/bc/scripts/ifs.bc
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#! /usr/bin/bc -q
|
||||||
|
|
||||||
|
a = 1
|
||||||
|
b = 2
|
||||||
|
c = 3
|
||||||
|
|
||||||
|
if (a == 1) if (b == 2) if (c == 3) print "Yay!\n"
|
||||||
|
|
||||||
|
define void g(x) {
|
||||||
|
print "g: x: ", x, "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 1) {
|
||||||
|
if (b == 2) {
|
||||||
|
if (c == 3) {
|
||||||
|
g(5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define void h(x) {
|
||||||
|
print "h: x: ", x, "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z == 0)
|
||||||
|
for (i = 0; i < 2; ++i)
|
||||||
|
if (a == 1)
|
||||||
|
for (j = 0; j < 2; ++j)
|
||||||
|
if (b == 2)
|
||||||
|
for (k = 0; k < 2; ++k)
|
||||||
|
if (c == 3) h(k)
|
||||||
|
|
||||||
|
define void i(x) {
|
||||||
|
print "i: x: ", x, "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z == 0) {
|
||||||
|
for (i = 0; i < 2; ++i) {
|
||||||
|
if (a == 1) {
|
||||||
|
for (j = 0; j < 2; ++j) {
|
||||||
|
if (b == 2) {
|
||||||
|
for (k = 0; k < 2; ++k) {
|
||||||
|
if (c == 3) i(k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
tests/bc/scripts/ifs.txt
Normal file
18
tests/bc/scripts/ifs.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Yay!
|
||||||
|
g: x: 5
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
i: x: 0
|
||||||
|
i: x: 1
|
||||||
|
i: x: 0
|
||||||
|
i: x: 1
|
||||||
|
i: x: 0
|
||||||
|
i: x: 1
|
||||||
|
i: x: 0
|
||||||
|
i: x: 1
|
33
tests/bc/scripts/ifs2.bc
Normal file
33
tests/bc/scripts/ifs2.bc
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#! /usr/bin/bc -q
|
||||||
|
|
||||||
|
a = 1
|
||||||
|
b = 2
|
||||||
|
c = 3
|
||||||
|
|
||||||
|
if (a == 1) if (b == 2) if (c == 3) print "Yay!\n"
|
||||||
|
|
||||||
|
define void g(x) {
|
||||||
|
print "g: x: ", x, "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 1) {
|
||||||
|
if (b == 2) {
|
||||||
|
if (c == 3) {
|
||||||
|
g(5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
define void h(x) {
|
||||||
|
print "h: x: ", x, "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z == 0)
|
||||||
|
for (i = 0; i < 2; ++i)
|
||||||
|
for (l = 0; l < 2; ++l)
|
||||||
|
if (a == 1)
|
||||||
|
for (j = 0; j < 2; ++j)
|
||||||
|
for (m = 0; m < 2; ++m)
|
||||||
|
if (b == 2)
|
||||||
|
for (k = 0; k < 2; ++k)
|
||||||
|
if (c == 3) h(k)
|
34
tests/bc/scripts/ifs2.txt
Normal file
34
tests/bc/scripts/ifs2.txt
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
Yay!
|
||||||
|
g: x: 5
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
||||||
|
h: x: 0
|
||||||
|
h: x: 1
|
@ -1 +1,4 @@
|
|||||||
for (i = 0; i < 3; ++i) if (2 < 3) 1
|
for (i = 0; i < 3; ++i) if (2 < 3) 1
|
||||||
|
if (3 < 4) for (i = 0; i < 3; ++i) if (4 < 5) 2
|
||||||
|
for (j = 0; j < 3; ++j) if (5 < 6) for (i = 0; i < 3; ++i) if (4 < 5) 3
|
||||||
|
if (6 < 7) for (j = 0; j < 3; ++j) if (5 < 6) for (i = 0; i < 3; ++i) if (4 < 5) 4
|
||||||
|
@ -1,3 +1,24 @@
|
|||||||
1
|
1
|
||||||
1
|
1
|
||||||
1
|
1
|
||||||
|
2
|
||||||
|
2
|
||||||
|
2
|
||||||
|
3
|
||||||
|
3
|
||||||
|
3
|
||||||
|
3
|
||||||
|
3
|
||||||
|
3
|
||||||
|
3
|
||||||
|
3
|
||||||
|
3
|
||||||
|
4
|
||||||
|
4
|
||||||
|
4
|
||||||
|
4
|
||||||
|
4
|
||||||
|
4
|
||||||
|
4
|
||||||
|
4
|
||||||
|
4
|
||||||
|
@ -92,10 +92,10 @@ checktest "$d" "$?" "stdin" "$testdir/$d/stdin_results.txt" "$out"
|
|||||||
if [ "$d" = "bc" ]; then
|
if [ "$d" = "bc" ]; then
|
||||||
|
|
||||||
cat "$testdir/$d/stdin1.txt" | "$exe" "$@" "$options" > "$out" 2> /dev/null
|
cat "$testdir/$d/stdin1.txt" | "$exe" "$@" "$options" > "$out" 2> /dev/null
|
||||||
checktest "$d" "$?" "stdin" "$testdir/$d/stdin1_results.txt" "$out"
|
checktest "$d" "$?" "stdin1" "$testdir/$d/stdin1_results.txt" "$out"
|
||||||
|
|
||||||
cat "$testdir/$d/stdin2.txt" | "$exe" "$@" "$options" > "$out" 2> /dev/null
|
cat "$testdir/$d/stdin2.txt" | "$exe" "$@" "$options" > "$out" 2> /dev/null
|
||||||
checktest "$d" "$?" "stdin" "$testdir/$d/stdin2_results.txt" "$out"
|
checktest "$d" "$?" "stdin2" "$testdir/$d/stdin2_results.txt" "$out"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -f "$out"
|
rm -f "$out"
|
||||||
|
Loading…
Reference in New Issue
Block a user