aboutsummaryrefslogtreecommitdiff
path: root/contrib/bc/src/bc_parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bc/src/bc_parse.c')
-rw-r--r--contrib/bc/src/bc_parse.c49
1 files changed, 31 insertions, 18 deletions
diff --git a/contrib/bc/src/bc_parse.c b/contrib/bc/src/bc_parse.c
index c2fc2186a065..8849c1b8e9c7 100644
--- a/contrib/bc/src/bc_parse.c
+++ b/contrib/bc/src/bc_parse.c
@@ -79,6 +79,7 @@ static bool bc_parse_inst_isLeaf(BcInst t) {
* that can legally end a statement. In bc's case, it could be a newline, a
* semicolon, and a brace in certain cases.
* @param p The parser.
+ * @return True if the token is a legal delimiter.
*/
static bool bc_parse_isDelimiter(const BcParse *p) {
@@ -128,6 +129,23 @@ static bool bc_parse_isDelimiter(const BcParse *p) {
}
/**
+ * Returns true if we are in top level of a function body. The POSIX grammar
+ * is defined such that anything is allowed after a function body, so we must
+ * use this function to detect that case when ending a function body.
+ * @param p The parser.
+ * @return True if we are in the top level of parsing a function body.
+ */
+static bool bc_parse_TopFunc(const BcParse *p) {
+
+ bool good = p->flags.len == 2;
+
+ uint16_t val = BC_PARSE_FLAG_BRACE | BC_PARSE_FLAG_FUNC_INNER;
+ val |= BC_PARSE_FLAG_FUNC;
+
+ return good && BC_PARSE_TOP_FLAG(p) == val;
+}
+
+/**
* Sets a previously defined exit label. What are labels? See the bc Parsing
* section of the Development manual (manuals/development.md).
* @param p The parser.
@@ -329,12 +347,8 @@ static void bc_parse_call(BcParse *p, const char *name, uint8_t flags) {
// not define it, it's a *runtime* error, not a parse error.
if (idx == BC_VEC_INVALID_IDX) {
- BC_SIG_LOCK;
-
idx = bc_program_insertFunc(p->prog, name);
- BC_SIG_UNLOCK;
-
assert(idx != BC_VEC_INVALID_IDX);
// Make sure that this pointer was not invalidated.
@@ -359,15 +373,13 @@ static void bc_parse_name(BcParse *p, BcInst *type,
{
char *name;
- BC_SIG_LOCK;
+ BC_SIG_ASSERT_LOCKED;
// We want a copy of the name since the lexer might overwrite its copy.
name = bc_vm_strdup(p->l.str.v);
BC_SETJMP_LOCKED(err);
- BC_SIG_UNLOCK;
-
// We need the next token to see if it's just a variable or something more.
bc_lex_next(&p->l);
@@ -431,9 +443,9 @@ static void bc_parse_name(BcParse *p, BcInst *type,
err:
// Need to make sure to unallocate the name.
- BC_SIG_MAYLOCK;
free(name);
BC_LONGJMP_CONT;
+ BC_SIG_MAYLOCK;
}
/**
@@ -887,7 +899,7 @@ static void bc_parse_endBody(BcParse *p, bool brace) {
bc_lex_next(&p->l);
// If the next token is not a delimiter, that is a problem.
- if (BC_ERR(!bc_parse_isDelimiter(p)))
+ if (BC_ERR(!bc_parse_isDelimiter(p) && !bc_parse_TopFunc(p)))
bc_parse_err(p, BC_ERR_PARSE_TOKEN);
}
@@ -1315,15 +1327,9 @@ static void bc_parse_func(BcParse *p) {
// Make sure the functions map and vector are synchronized.
assert(p->prog->fns.len == p->prog->fn_map.len);
- // Must lock signals because vectors are changed, and the vector functions
- // expect signals to be locked.
- BC_SIG_LOCK;
-
// Insert the function by name into the map and vector.
idx = bc_program_insertFunc(p->prog, p->l.str.v);
- BC_SIG_UNLOCK;
-
// Make sure the insert worked.
assert(idx);
@@ -1753,13 +1759,21 @@ static void bc_parse_stmt(BcParse *p) {
// Make sure semicolons are eaten.
while (p->l.t == BC_LEX_SCOLON) bc_lex_next(&p->l);
+
+ // POSIX's grammar does not allow a function definition after a semicolon
+ // without a newline, so check specifically for that case and error if
+ // the POSIX standard flag is set.
+ if (p->l.last == BC_LEX_SCOLON && p->l.t == BC_LEX_KW_DEFINE && BC_IS_POSIX)
+ {
+ bc_parse_err(p, BC_ERR_POSIX_FUNC_AFTER_SEMICOLON);
+ }
}
void bc_parse_parse(BcParse *p) {
assert(p);
- BC_SETJMP(exit);
+ BC_SETJMP_LOCKED(exit);
// We should not let an EOF get here unless some partial parse was not
// completed, in which case, it's the user's fault.
@@ -1780,13 +1794,12 @@ void bc_parse_parse(BcParse *p) {
exit:
- BC_SIG_MAYLOCK;
-
// We need to reset on error.
if (BC_ERR(((vm.status && vm.status != BC_STATUS_QUIT) || vm.sig)))
bc_parse_reset(p);
BC_LONGJMP_CONT;
+ BC_SIG_MAYLOCK;
}
/**