arctic/src/arctic.c

123 lines
3.8 KiB
C

#include "arctic.h"
#include <string.h>
const char ARCTIC_CODE_PAGE[97] =
"0123456789ABCDEF"
"GHIJKLMNOPQRSTUV"
"WXYZabcdefghijkl"
"mnopqrstuvwxyz_."
"+-*/%\\|$@<{=}>,;"
"&^![]?~:()'\"` #\n"
;
/* ops with an immediate argument */
#define FOR_IMMEDIATE_OPS(X) \
X('0') X('G') X('H') X('L') X('M') X('P') X('Q') X('d') X('o') X('u') \
X('@') X('<') X('{') X('=') X('}') X('>') X(',') X(';') X('[') X(']')
#define FOR_PLAIN_OPS(X) \
X('1') X('2') X('3') X('4') X('5') X('6') X('7') X('8') X('9') X('A') \
X('B') X('C') X('D') X('E') X('F') X('I') X('J') X('K') X('N') X('O') \
X('R') X('S') X('U') X('V') X('W') X('X') X('Y') X('Z') X('a') X('b') \
X('c') X('e') X('f') X('g') X('h') X('i') X('j') X('k') X('l') X('m') \
X('n') X('p') X('q') X('r') X('s') X('t') X('v') X('w') X('x') X('y') \
X('z') X('_') X('.') X('+') X('-') X('*') X('/') X('%') X('\\') X('|') \
X('&') X('^') X('!') X('?') X('(') X(')') X('`')
#define CASE(X, ...) case X:
#define chrncat(str, chr, n, fail) do { \
char *last; \
for (last = str; *last; last++) { \
if (last >= str + n) { \
fail; \
} \
} \
*last++ = chr; \
*last = 0; \
} while (0)
enum ArcticErrorCode arctic_scan(struct ArcticScanner *scanner, char next) {
switch (scanner->buf[0]) {
case 0: /* initial state */
switch (next) {
case ' ':
return ARCTIC_OK;
FOR_IMMEDIATE_OPS(CASE)
case '#':
case ':':
case '\"':
case '\'':
scanner->buf[0] = next;
scanner->buf[1] = 0;
return ARCTIC_OK;
FOR_PLAIN_OPS(CASE)
case '\n':
scanner->op_callback(next, 0, scanner->data);
return ARCTIC_OK;
default:
return ARCTIC_UNEXPECTED_CHAR;
}
case '#': /* comment */
if (next == '\n')
scanner->buf[0] = 0;
return ARCTIC_OK;
case '"': /* section switch */
if (next == '"') {
scanner->section_callback(scanner->buf + 1, scanner->data);
scanner->buf[0] = 0;
} else {
chrncat(
scanner->buf, next, ARCTIC_BUFSIZE,
return ARCTIC_BUFFER_FULL
);
}
return ARCTIC_OK;
case ':': /* label name */
if (next == ' ' || next == '\n' || next == '#') {
scanner->label_callback(scanner->buf + 1, scanner->data);
scanner->buf[0] = (next == '#' ? '#' : 0);
} else {
chrncat(
scanner->buf, next, ARCTIC_BUFSIZE,
return ARCTIC_BUFFER_FULL
);
}
return ARCTIC_OK;
case '\'': /* data injection */
if (next == '\'') {
scanner->data_callback(scanner->buf + 1, scanner->data);
scanner->buf[0] = 0;
} else {
chrncat(
scanner->buf, next, ARCTIC_BUFSIZE,
return ARCTIC_BUFFER_FULL
);
}
return ARCTIC_OK;
FOR_IMMEDIATE_OPS(CASE) /* immediate ops */
if (next == ' ' || next == '\n' || next == '#') {
scanner->op_callback(scanner->buf[0], scanner->buf + 1, scanner->data);
scanner->buf[0] = (next == '#' ? '#' : 0);
} else {
chrncat(
scanner->buf, next, ARCTIC_BUFSIZE,
return ARCTIC_BUFFER_FULL
);
}
return ARCTIC_OK;
default:
return ARCTIC_INVALID_STATE;
}
}