344 lines
10 KiB
C
344 lines
10 KiB
C
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
|
│ │
|
|
│ This program is free software; you can redistribute it and/or modify │
|
|
│ it under the terms of the GNU General Public License as published by │
|
|
│ the Free Software Foundation; version 2 of the License. │
|
|
│ │
|
|
│ This program is distributed in the hope that it will be useful, but │
|
|
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
|
|
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
|
|
│ General Public License for more details. │
|
|
│ │
|
|
│ You should have received a copy of the GNU General Public License │
|
|
│ along with this program; if not, write to the Free Software │
|
|
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
|
│ 02110-1301 USA │
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
#include "libc/bits/bits.h"
|
|
#include "libc/bits/safemacros.internal.h"
|
|
#include "libc/calls/calls.h"
|
|
#include "libc/conv/conv.h"
|
|
#include "libc/errno.h"
|
|
#include "libc/log/log.h"
|
|
#include "libc/macros.h"
|
|
#include "libc/mem/mem.h"
|
|
#include "libc/nexgen32e/bsf.h"
|
|
#include "libc/nexgen32e/bsr.h"
|
|
#include "libc/str/str.h"
|
|
#include "libc/sysv/consts/o.h"
|
|
#include "libc/time/time.h"
|
|
#include "libc/x/x.h"
|
|
#include "o/tool/tags/tags.c.inc"
|
|
#include "o/tool/tags/tags.h.inc"
|
|
#include "tool/tags/tags.h"
|
|
|
|
static jmp_buf jb;
|
|
static int g_line;
|
|
static int g_column;
|
|
static const char *g_file;
|
|
static yyParser g_parser[1];
|
|
|
|
noreturn static void Error(const char *msg) {
|
|
fprintf(stderr, "%s:%d:%d: %s\n", g_file, g_line, g_column, msg);
|
|
longjmp(jb, 1);
|
|
}
|
|
|
|
noreturn static void SyntaxError(void) {
|
|
Error("SYNTAX ERROR");
|
|
}
|
|
|
|
noreturn static void LexError(void) {
|
|
Error("LEX ERROR");
|
|
}
|
|
|
|
noreturn static void MissingArgumentError(void) {
|
|
Error("MISSING ARGUMENT");
|
|
}
|
|
|
|
noreturn static void MissingFunctionError(void) {
|
|
Error("MISSING FUNCTION");
|
|
}
|
|
|
|
noreturn static void SyscallError(const char *name) {
|
|
fprintf(stderr, "ERROR: %s[%s]: %d\n", name, g_file, errno);
|
|
exit(1);
|
|
}
|
|
|
|
static void ExprsFree(struct Exprs *n) {
|
|
if (n) {
|
|
ExprsFree(n->n);
|
|
free(n);
|
|
}
|
|
}
|
|
|
|
static struct Exprs *ExprsAppend(struct Exprs *n, long double x) {
|
|
struct Exprs *a;
|
|
a = malloc(sizeof(struct Exprs));
|
|
a->n = n;
|
|
a->x = x;
|
|
return a;
|
|
}
|
|
|
|
static long double ParseExpr(struct Token t) {
|
|
char *ep;
|
|
ep = t.s + t.n;
|
|
if (t.s[0] == '0') {
|
|
return strtoumax(t.s, &ep, 0);
|
|
} else {
|
|
return strtod(t.s, &ep);
|
|
}
|
|
}
|
|
|
|
static long double CallFunction(struct Token fn, struct Exprs *args) {
|
|
return 0;
|
|
}
|
|
|
|
static void Tokenize(const char *s, size_t size) {
|
|
int kw;
|
|
size_t n;
|
|
char *se;
|
|
for (se = s + size; s < se; s += n, ++g_column) {
|
|
n = 1;
|
|
switch (*s & 0xff) {
|
|
case ' ':
|
|
case '\t':
|
|
case '\v':
|
|
case '\r':
|
|
case 0x0C:
|
|
break;
|
|
case '\n':
|
|
++g_line;
|
|
g_column = 0;
|
|
break;
|
|
case 'A' ... 'Z':
|
|
case 'a' ... 'z':
|
|
n = strspn(s, "$"
|
|
"0123456789"
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
"abcdefghijklmnopqrstuvwxyz");
|
|
if ((kw = GetKeyword(s, n)) != -1) {
|
|
Parse(g_parser, kw, (struct Token){s, n});
|
|
} else {
|
|
Parse(g_parser, TK_SYMBOL, (struct Token){s, n});
|
|
}
|
|
break;
|
|
case '0':
|
|
n = strspn(s, "xXbB0123456789abcdefABCDEF");
|
|
Parse(g_parser, TK_I_CONSTANT, (struct Token){s, n});
|
|
n += strspn(s + n, "LUlu");
|
|
break;
|
|
case '1' ... '9':
|
|
n = strspn(s, "0123456789.");
|
|
if (s[n] == 'e' || s[n] == 'E') {
|
|
++n;
|
|
if (s[n] == '+' || s[n] == '-') ++n;
|
|
n += strspn(s + n, "0123456789");
|
|
}
|
|
Parse(g_parser, memchr(s, '.', n) ? TK_F_CONSTANT : TK_I_CONSTANT,
|
|
(struct Token){s, n});
|
|
n += strspn(s + n, "LUlu");
|
|
break;
|
|
case ';':
|
|
Parse(g_parser, TK_SEMI, (struct Token){0, 0});
|
|
break;
|
|
case '(':
|
|
Parse(g_parser, TK_LP, (struct Token){0, 0});
|
|
break;
|
|
case ')':
|
|
Parse(g_parser, TK_RP, (struct Token){0, 0});
|
|
break;
|
|
case '[':
|
|
Parse(g_parser, TK_LSB, (struct Token){0, 0});
|
|
break;
|
|
case ']':
|
|
Parse(g_parser, TK_RSB, (struct Token){0, 0});
|
|
break;
|
|
case '{':
|
|
Parse(g_parser, TK_LCB, (struct Token){0, 0});
|
|
break;
|
|
case '}':
|
|
Parse(g_parser, TK_RCB, (struct Token){0, 0});
|
|
break;
|
|
case '?':
|
|
Parse(g_parser, TK_QUESTION, (struct Token){0, 0});
|
|
break;
|
|
case ':':
|
|
Parse(g_parser, TK_COLON, (struct Token){0, 0});
|
|
break;
|
|
case ',':
|
|
Parse(g_parser, TK_COMMA, (struct Token){0, 0});
|
|
break;
|
|
case '^':
|
|
if (s[1] == '=') {
|
|
Parse(g_parser, TK_XOR_ASSIGN, (struct Token){0, 0});
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_XOR, (struct Token){0, 0});
|
|
}
|
|
break;
|
|
case '%':
|
|
if (s[1] == '=') {
|
|
Parse(g_parser, TK_REM_ASSIGN, (struct Token){0, 0});
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_REM, (struct Token){0, 0});
|
|
}
|
|
break;
|
|
case '.':
|
|
Parse(g_parser, TK_DOT, (struct Token){0, 0});
|
|
break;
|
|
case '+':
|
|
if (s[1] == '=') {
|
|
Parse(g_parser, TK_ADD_ASSIGN, (struct Token){0, 0});
|
|
++n;
|
|
} else if (s[1] == '+') {
|
|
Parse(g_parser, TK_INC, (struct Token){0, 0});
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_ADD, (struct Token){0, 0});
|
|
}
|
|
break;
|
|
case '-':
|
|
if (s[1] == '=') {
|
|
Parse(g_parser, TK_SUB_ASSIGN, (struct Token){0, 0});
|
|
++n;
|
|
} else if (s[1] == '-') {
|
|
Parse(g_parser, TK_DEC, (struct Token){0, 0});
|
|
++n;
|
|
} else if (s[1] == '>') {
|
|
Parse(g_parser, TK_ARROW, (struct Token){0, 0});
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_SUB, (struct Token){0, 0});
|
|
}
|
|
break;
|
|
case '~':
|
|
Parse(g_parser, TK_TILDE, (struct Token){0, 0});
|
|
break;
|
|
case '/':
|
|
if (s[1] == '=') {
|
|
Parse(g_parser, TK_DIV_ASSIGN, (struct Token){0, 0});
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_DIV, (struct Token){0, 0});
|
|
}
|
|
break;
|
|
case '*':
|
|
if (s[1] == '=') {
|
|
Parse(g_parser, TK_MUL_ASSIGN, (struct Token){0, 0});
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_STAR, (struct Token){0, 0});
|
|
}
|
|
break;
|
|
case '|':
|
|
if (s[1] == '|') {
|
|
Parse(g_parser, TK_OR_LOGICAL, (struct Token){0, 0});
|
|
++n;
|
|
} else if (s[1] == '=') {
|
|
Parse(g_parser, TK_OR_ASSIGN, (struct Token){0, 0});
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_OR, (struct Token){0, 0});
|
|
}
|
|
break;
|
|
case '&':
|
|
if (s[1] == '&') {
|
|
Parse(g_parser, TK_AND_LOGICAL, (struct Token){0, 0});
|
|
++n;
|
|
} else if (s[1] == '=') {
|
|
Parse(g_parser, TK_AND_ASSIGN, (struct Token){0, 0});
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_AND, (struct Token){0, 0});
|
|
}
|
|
break;
|
|
case '!':
|
|
if (s[1] == '=') {
|
|
Parse(g_parser, TK_NOTEQUAL, (struct Token){0, 0});
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_EXCLAIM, (struct Token){0, 0});
|
|
}
|
|
break;
|
|
case '=':
|
|
if (s[1] == '=') {
|
|
Parse(g_parser, TK_EQUAL, (struct Token){0, 0});
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_EQ, (struct Token){0, 0});
|
|
}
|
|
break;
|
|
case '>':
|
|
if (s[1] == '=') {
|
|
Parse(g_parser, TK_GE, (struct Token){0, 0});
|
|
++n;
|
|
} else if (s[1] == '>') {
|
|
if (s[2] == '=') {
|
|
Parse(g_parser, TK_SHR_ASSIGN, (struct Token){0, 0});
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_SHR, (struct Token){0, 0});
|
|
}
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_GT, (struct Token){0, 0});
|
|
}
|
|
break;
|
|
case '<':
|
|
if (s[1] == '=') {
|
|
Parse(g_parser, TK_LE, (struct Token){0, 0});
|
|
++n;
|
|
} else if (s[1] == '<') {
|
|
if (s[2] == '=') {
|
|
Parse(g_parser, TK_SHL_ASSIGN, (struct Token){0, 0});
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_SHL, (struct Token){0, 0});
|
|
}
|
|
++n;
|
|
} else {
|
|
Parse(g_parser, TK_LT, (struct Token){0, 0});
|
|
}
|
|
break;
|
|
default:
|
|
LexError();
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
int i;
|
|
int ec;
|
|
int fd;
|
|
size_t n;
|
|
char *buf;
|
|
ssize_t rc;
|
|
size_t bufcap;
|
|
bufcap = BIGPAGESIZE;
|
|
buf = malloc(bufcap);
|
|
if (!(ec = setjmp(jb))) {
|
|
for (i = 1; i < argc; ++i) {
|
|
g_file = argv[i];
|
|
g_line = 0;
|
|
g_column = 0;
|
|
n = 0; /* wut */
|
|
if ((fd = open(g_file, O_RDONLY)) == -1) SyscallError("open");
|
|
ParseInit(g_parser);
|
|
for (;;) {
|
|
if ((rc = read(fd, buf, bufcap)) == -1) SyscallError("read");
|
|
if (!(n = rc)) break;
|
|
Tokenize(buf, n);
|
|
}
|
|
close(fd);
|
|
Parse(g_parser, 0, (struct Token){0, 0});
|
|
ParseFinalize(g_parser);
|
|
}
|
|
}
|
|
free(buf);
|
|
return ec;
|
|
}
|