blob: 0a2724748f7a04691d930e139ca0da3c755c8043 [file] [log] [blame]
/*
* *****************************************************************************
*
* Copyright 2018 Gavin D. Howard
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* *****************************************************************************
*
* Code common to the parsers.
*
*/
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <status.h>
#include <vector.h>
#include <lex.h>
#include <parse.h>
#include <program.h>
BcStatus bc_parse_pushName(BcVec *code, char *name) {
BcStatus s = BC_STATUS_SUCCESS;
size_t i, len = strlen(name);
for (i = 0; !s && i < len; ++i) s = bc_vec_pushByte(code, (char) name[i]);
if (s) return s;
free(name);
return bc_vec_pushByte(code, BC_PARSE_STREND);
}
BcStatus bc_parse_pushIndex(BcVec *code, size_t idx) {
BcStatus s;
unsigned char amt, i, nums[sizeof(size_t)];
for (amt = 0; idx; ++amt) {
nums[amt] = (char) idx;
idx = (idx & ((unsigned long) ~(UINT8_MAX))) >> sizeof(char) * CHAR_BIT;
}
if ((s = bc_vec_pushByte(code, amt))) return s;
for (i = 0; !s && i < amt; ++i) s = bc_vec_pushByte(code, nums[i]);
return s;
}
BcStatus bc_parse_number(BcParse *p, BcVec *code, BcInst *prev, size_t *nexs) {
BcStatus s;
char *num;
size_t idx = p->prog->consts.len;
if (!(num = strdup(p->l.t.v.v))) return BC_STATUS_ALLOC_ERR;
if ((s = bc_vec_push(&p->prog->consts, &num))) {
free(num);
return s;
}
if ((s = bc_vec_pushByte(code, BC_INST_NUM))) return s;
if ((s = bc_parse_pushIndex(code, idx))) return s;
++(*nexs);
(*prev) = BC_INST_NUM;
return s;
}
BcStatus bc_parse_reset(BcParse *p, BcStatus s) {
if (p->func) {
BcFunc *func = bc_vec_item(&p->prog->fns, p->func);
func->nparams = 0;
bc_vec_npop(&func->code, func->code.len);
bc_vec_npop(&func->autos, func->autos.len);
bc_vec_npop(&func->labels, func->labels.len);
p->func = 0;
}
p->l.idx = p->l.len;
p->l.t.t = BC_LEX_EOF;
p->auto_part = p->nbraces = 0;
bc_vec_npop(&p->flags, p->flags.len - 1);
bc_vec_npop(&p->exits, p->exits.len);
bc_vec_npop(&p->conds, p->conds.len);
bc_vec_npop(&p->ops, p->ops.len);
return bc_program_reset(p->prog, s);
}
BcStatus bc_parse_create(BcParse *p, BcProgram *prog,
BcParseParse parse, BcLexNext next)
{
BcStatus s;
uint8_t flags = 0;
assert(p && prog);
if ((s = bc_lex_init(&p->l, next))) return s;
if ((s = bc_vec_init(&p->flags, sizeof(uint8_t), NULL))) goto flags_err;
if ((s = bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL))) goto exit_err;
if ((s = bc_vec_init(&p->conds, sizeof(size_t), NULL))) goto cond_err;
if ((s = bc_vec_push(&p->flags, &flags))) goto push_err;
if ((s = bc_vec_init(&p->ops, sizeof(BcLexType), NULL))) goto push_err;
p->parse = parse;
p->prog = prog;
p->auto_part = p->func = p->nbraces = 0;
return s;
push_err:
bc_vec_free(&p->conds);
cond_err:
bc_vec_free(&p->exits);
exit_err:
bc_vec_free(&p->flags);
flags_err:
bc_lex_free(&p->l);
return s;
}
void bc_parse_free(BcParse *p) {
assert(p);
bc_vec_free(&p->flags);
bc_vec_free(&p->exits);
bc_vec_free(&p->conds);
bc_vec_free(&p->ops);
bc_lex_free(&p->l);
}