blob: 99823ecce07cc73a109064bb5f0d4bb7f04380aa [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.
*
* *****************************************************************************
*
* The lexer for dc.
*
*/
#include <ctype.h>
#include <status.h>
#include <lex.h>
#include <dc.h>
#include <vm.h>
BcStatus dc_lex_register(BcLex *l) {
BcStatus s;
if (l->t.t == BC_LEX_WHITESPACE) {
if (!bcg.exreg) s = BC_STATUS_LEX_EXTENDED_REG;
else s = bc_lex_name(l);
}
else {
bc_vec_npop(&l->t.v, l->t.v.len);
if ((s = bc_vec_pushByte(&l->t.v, l->buffer[l->idx - 1]))) return s;
s = bc_vec_pushByte(&l->t.v, '\0');
}
return s;
}
BcStatus dc_lex_string(BcLex *l) {
BcStatus s;
size_t depth = 1, nls = 0, idx, i = l->idx;
char c;
l->t.t = BC_LEX_STRING;
bc_vec_npop(&l->t.v, l->t.v.len);
for (idx = i; (c = l->buffer[i]) && depth; ++i) {
depth += (c == '[');
depth -= (c == ']');
nls += (c == '\n');
if (c == '#') {
bc_lex_lineComment(l);
// We increment by 1 to skip the newline.
if (l->buffer[l->idx]) {
i = l->idx + 1;
++nls;
}
}
else {
if (depth && (s = bc_vec_push(&l->t.v, &c))) return s;
if (c == '\\') {
depth -= (l->buffer[i + 1] == '[');
depth += (l->buffer[i + 1] == ']');
}
}
}
if (c == '\0') {
l->idx = i;
return BC_STATUS_LEX_NO_STRING_END;
}
if ((s = bc_vec_pushByte(&l->t.v, '\0'))) return s;
if (i - idx > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
l->idx = i + 1;
l->line += nls;
return BC_STATUS_SUCCESS;
}
BcStatus dc_lex_token(BcLex *l) {
BcStatus s = BC_STATUS_SUCCESS;
char c = l->buffer[l->idx++], c2;
size_t i;
for (i = 0; i < dc_lex_regs_len; ++i) {
if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
}
if (c >= '%' && (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
return s;
// This is the workhorse of the lexer.
switch (c) {
case '\0':
{
l->t.t = BC_LEX_EOF;
break;
}
case '\n':
case '\t':
case '\v':
case '\f':
case '\r':
case ' ':
{
l->newline = c == '\n';
bc_lex_whitespace(l);
break;
}
case '!':
{
c2 = l->buffer[l->idx];
if (c2 == '=') l->t.t = BC_LEX_OP_REL_NE;
else if (c2 == '<') l->t.t = BC_LEX_OP_REL_GE;
else if (c2 == '>') l->t.t = BC_LEX_OP_REL_LE;
else return BC_STATUS_LEX_BAD_CHAR;
++l->idx;
break;
}
case '#':
{
bc_lex_lineComment(l);
break;
}
case '.':
{
if (isdigit(l->buffer[l->idx])) s = bc_lex_number(l, c);
else s = BC_STATUS_LEX_BAD_CHAR;
break;
}
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
{
s = bc_lex_number(l, c);
break;
}
case '[':
{
s = dc_lex_string(l);
break;
}
default:
{
l->t.t = BC_LEX_INVALID;
s = BC_STATUS_LEX_BAD_CHAR;
break;
}
}
return s;
}