Browse Source

inital commit

remotes/origin/HEAD
Seth Stubbs 4 months ago
commit
f17285ec6c
  1. 23
      Makefile
  2. 1
      README.md
  3. 1
      TODO
  4. 0
      src/main.c
  5. 0
      src/uasm.c
  6. 8
      src/uasm.h
  7. 145
      src/ulex.c
  8. 49
      src/ulex.h
  9. 24
      src/umem.h
  10. 84
      src/uparse.c
  11. 29
      src/uparse.h
  12. 12
      src/uxncle.h
  13. 7
      test.uxnc

23
Makefile

@ -0,0 +1,23 @@
CC=clang
CFLAGS=-fPIE -Wall -O3 -Isrc -std=c99
LDFLAGS=-lm #-fsanitize=address
OUT=bin/uxnscr
CHDR=\
src/ulex.h\
CSRC=\
src/ulex.c\
src/main.c
COBJ=$(CSRC:.c=.o)
.c.o:
$(CC) -c $(CFLAGS) $< -o $@
$(OUT): $(COBJ) $(CHDR)
mkdir -p bin
$(CC) $(COBJ) $(LDFLAGS) -o $(OUT)
clean:
rm -rf $(COBJ) $(OUT)

1
README.md

@ -0,0 +1 @@
Uxncle is a small C-like programming language for the [Uxn](https://git.sr.ht/~rabbits/uxn) virtual machine. This will compile your source into compatible .tal files for the uxntal assembler, to then be compiled into bytecode.

1
TODO

@ -0,0 +1 @@
- preprocessor directive to include binary files & define their location as a pointer

0
src/main.c

0
src/uasm.c

8
src/uasm.h

@ -0,0 +1,8 @@
#ifndef UASM_H
#define UASM_H
#define PAGE_PROGRAM 0x0100
#define STACK_LIMIT 256
#endif

145
src/ulex.c

@ -0,0 +1,145 @@
#include "umem.h"
#include "ulex.h"
typedef struct {
UTokenType type;
const char *word;
int len;
} UReservedWord;
UReservedWord reservedWords[] = {
{TOKEN_BYTE, "byte", 4},
{TOKEN_BYTE16, "byte16", 6},
{TOKEN_VOID, "void", 4}
};
void UL_initLexState(ULexState *state, const char *src) {
state->current = src;
state->line = 1;
state->last = TOKEN_ERR;
}
UToken makeToken(ULexState *state, UTokenType type) {
UToken token;
token.str = state->start;
token.len = state->current - state->start;
token.type = type;
// update the state's last token type
state->last = type;
return token;
}
/* ==================================[[ char helper functions ]]================================== */
/* check if the current character is a null terminator */
int isEnd(ULexState *state) {
return *state->current == '\0';
}
/* increment the current pointer and return the previous character */
char next(ULexState *state) {
state->current++;
return state->current[-1];
}
char peek(ULexState *state) {
return *state->current;
}
char peekNext(ULexState *state) {
if (isEnd(state))
return '\0';
/* return the next character */
return state->current[1];
}
int isAlpha(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; /* identifiers can have '_' */
}
int isNumeric(char c) {
return c >= '0' && c <= '9';
}
int isWhitespace(char c) {
return c == ' ' || c == '\n' || c == '\r' || c == '\t';
}
/* ==================================[[ parse long tokens ]]================================== */
void skipWhitespace(ULexState *state) {
/* consume all whitespace */
while (isWhitespace(peek(state))) {
if (peek(state) == '\n') /* if it's a new line, make sure we count it */
state->line++;
next(state);
}
}
UTokenType identifierType(ULexState *state) {
int len = state->start - state->current;
/* walk through each reserved word and compare it */
for (int i = 0; i < sizeof(reservedWords)/sizeof(UReservedWord); i++) {
if (reservedWords[i].len == len && memcmp(state->start, reservedWords[i].word, len))
return reservedWords[i].type;
}
/* it wasn't found in the reserved word list */
return TOKEN_IDENT;
}
UToken readNumber(ULexState *state) {
while (isNumeric(peek(state)))
next(state);
return makeToken(state, TOKEN_NUMBER);
}
UToken readIdentifier(ULexState *state) {
while (!isEnd(state) && (isAlpha(peek(state)) || isNumerical(peek(state))))
next(state);
return makeToken(state, identifierType(state)); /* is it a reserved word? */
}
UToken UL_scanNext(ULexState *state) {
char c;
/* mark start of token and check if it's the end of the string */
state->start = state->current;
if (isEnd(state))
return makeToken(state, TOKEN_EOF);
/* skip all whitespace characters then grab the next character */
skipWhitespace(state);
c = next(state);
switch (c) {
/* single character tokens */
case '(': return makeToken(state, TOKEN_LEFT_PAREN);
case ')': return makeToken(state, TOKEN_RIGHT_PAREN);
case '{': return makeToken(state, TOKEN_LEFT_BRACE);
case '}': return makeToken(state, TOKEN_RIGHT_BRACE);
case '[': return makeToken(state, TOKEN_LEFT_BRACKET);
case ']': return makeToken(state, TOKEN_RIGHT_BRACKET);
case '+': return makeToken(state, TOKEN_PLUS);
case '-': return makeToken(state, TOKEN_MINUS);
case '/': return makeToken(state, TOKEN_SLASH);
case '*': return makeToken(state, TOKEN_STAR);
case ';': return makeToken(state, TOKEN_COLON);
case '\0': return makeToken(state, TOKEN_EOF);
default:
if (isNumeric(c))
return readNumber(state);
/* its not a number, its probably a keyword or identifier */
if (isAlpha(c))
return readIdentifier(state);
}
/* it's none of those, so it's an unrecognized token. return an error result for now */
return makeToken(state, TOKEN_ERR);
}

49
src/ulex.h

@ -0,0 +1,49 @@
#ifndef ULEX_H
#define ULEX_H
typedef enum {
/* keywords */
TOKEN_BYTE,
TOKEN_BYTE16,
TOKEN_VOID,
/* literals */
TOKEN_IDENT,
TOKEN_NUMBER,
TOKEN_LEFT_BRACE,
TOKEN_RIGHT_BRACE,
TOKEN_LEFT_PAREN,
TOKEN_RIGHT_PAREN,
TOKEN_LEFT_BRACKET,
TOKEN_RIGHT_BRACKET,
TOKEN_COLON,
TOKEN_POUND,
TOKEN_PLUS,
TOKEN_MINUS,
TOKEN_SLASH,
TOKEN_STAR,
TOKEN_EOF, /* end of file */
TOKEN_ERR /* error type */
} UTokenType;
typedef struct {
UTokenType type;
char *str;
int len;
} UToken;
typedef struct {
char *current;
char *start;
int line;
UTokenType last;
} ULexState;
void UL_initLexState(ULexState *state, const char *src);
/* grabs the next token from the sequence */
UToken UL_scanNext(ULexState *state);
#endif

24
src/umem.h

@ -0,0 +1,24 @@
#ifndef UMEM_H
#define UMEM_H
#include "uxncle.h"
#define GROW_FACTOR 2
#define UM_realloc(buf, size) \
realloc(buf, size);
#define UM_freearray(buf) \
UM_realloc(buf, NULL);
#define UM_free(buf) \
UM_realloc(buf, NULL);
#define UM_growarray(type, buf, count, capacity) \
if (count >= capacity || buf == NULL) { \
int old = capacity; \
capacity = old * GROW_FACTOR; \
buf = (type*)UM_realloc(buf, sizeof(type) * capacity); \
}
#endif

84
src/uparse.c

@ -0,0 +1,84 @@
#include "umem.h"
#include "uparse.h"
typedef enum {
PREC_NONE,
PREC_ASSIGNMENT, // =
PREC_TERM, // + -
PREC_FACTOR, // * /
PREC_PRIMARY // everything else
} Precedence;
typedef UASTNode* (*ParseFunc)(UParseState* pstate);
typedef struct {
ParseFunc prefix;
ParseFunc infix;
Precedence level;
} ParseRule;
/* ==================================[[ generic helper functions ]]================================== */
UASTNode *newNode(UParseState *state, UASTNodeType type, UASTNode *left, UASTNode *right) {
UASTNode *node = UM_realloc(NULL, sizeof(UASTNode));
node->left = left;
node->right = right;
return node;
}
void errorAt(UToken *token, int line, const char *fmt, va_list args) {
print("Syntax error at '%*s' on line %d", token->len, token->str, line);
vprintf(fmt, args);
exit(0);
}
void error(UParseState *state, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
errorAt(&state->current, state->lstate.line, fmt, args);
va_end(args);
}
void next(UParseState *state) {
state->previous = state->current;
state->current = UL_scanNext(&state->lstate);
}
UASTNode *binExpression(UParseState *state) {
}
ParseRule ruleTable[] = {
/* keywords */
{NULL, NULL, PREC_NONE}, /* TOKEN_BYTE */
{NULL, NULL, PREC_NONE}, /* TOKEN_BYTE16 */
{NULL, NULL, PREC_NONE}, /* TOKEN_VOID */
/* literals */
{NULL, NULL, PREC_NONE}, /* TOKEN_IDENT */
{NULL, NULL, PREC_NONE}, /* TOKEN_NUMBER */
{NULL, NULL, PREC_NONE}, /* TOKEN_LEFT_BRACE */
{NULL, NULL, PREC_NONE}, /* TOKEN_RIGHT_BRACE */
{NULL, NULL, PREC_NONE}, /* TOKEN_LEFT_PAREN */
{NULL, NULL, PREC_NONE}, /* TOKEN_RIGHT_PAREN */
{NULL, NULL, PREC_NONE}, /* TOKEN_LEFT_BRACKET */
{NULL, NULL, PREC_NONE}, /* TOKEN_RIGHT_BRACKET */
{NULL, NULL, PREC_NONE}, /* TOKEN_COLON */
{NULL, NULL, PREC_NONE}, /* TOKEN_POUND */
{NULL, NULL, PREC_NONE}, /* TOKEN_PLUS */
{NULL, NULL, PREC_NONE}, /* TOKEN_MINUS */
{NULL, NULL, PREC_NONE}, /* TOKEN_SLASH */
{NULL, NULL, PREC_NONE}, /* TOKEN_STAR */
{NULL, NULL, PREC_NONE}, /* TOKEN_EOF */
{NULL, NULL, PREC_NONE}, /* TOKEN_ERR */
};
UASTNode *UP_parseSource(const char *src) {
UParseState state;
UL_initLexState(&state.lstate, src);
return NULL;
}

29
src/uparse.h

@ -0,0 +1,29 @@
#ifndef UPARSE_H
#define UPARSE_H
#include "ulex.h"
typedef enum {
NODE_ADD,
NODE_SUB
} UASTNodeType;
typedef struct s_UASTNode {
UASTNodeType type;
struct s_UASTNode *left;
struct s_UASTNode *right;
union {
int num;
};
} UASTNode;
typedef struct {
ULexState lstate;
UToken current;
UToken previous;
} UParseState;
/* returns the base AST node, or NULL if a syntax error occurred */
UASTNode *UP_parseSource(const char *src);
#endif

12
src/uxncle.h

@ -0,0 +1,12 @@
#ifndef UCOMMON_H
#define UCOMMON_H
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#endif

7
test.uxnc

@ -0,0 +1,7 @@
short sub(short a, short b) {
return a - b;
}
void main() {
sub(5, 4);
}
Loading…
Cancel
Save