added stdio functionality

This commit is contained in:
Conál Paxton 2026-02-18 17:54:22 -05:00
parent 990391144c
commit 78f56d916c
19 changed files with 675 additions and 55 deletions

BIN
bin/os

Binary file not shown.

BIN
image.hdd

Binary file not shown.

2
limine

@ -1 +1 @@
Subproject commit e0e61c946933696453f591da525ab1f8a66a553d
Subproject commit eecf8d682a749701691e31b89f66f330f525c611

Binary file not shown.

View File

@ -1,6 +1,7 @@
obj/src/main.c.o: src/main.c src/../include/limine.h src/prompt/lex.h \
src/prompt/file.h src/acpi.h src/common.h src/alloc.h src/apic.h \
src/map.h src/print.h
src/kbd.h src/map.h src/print.h src/lib/stdio.h src/lib/malloc.h \
src/lib/../common.h src/lib/../kbd.h src/lib/../print.h
src/../include/limine.h:
src/prompt/lex.h:
src/prompt/file.h:
@ -8,5 +9,11 @@ src/acpi.h:
src/common.h:
src/alloc.h:
src/apic.h:
src/kbd.h:
src/map.h:
src/print.h:
src/lib/stdio.h:
src/lib/malloc.h:
src/lib/../common.h:
src/lib/../kbd.h:
src/lib/../print.h:

Binary file not shown.

2
run.sh
View File

@ -1 +1 @@
qemu-system-x86_64 image.hdd
/mnt/c/'Program Files'/qemu/qemu-system-x86_64.exe image.hdd

View File

@ -3,6 +3,19 @@
#include "common.h"
#include "print.h"
#ifdef DBG
#define dprint(x) print(x)
#define dprint8(x) print8(x)
#define dprint16(x) print16(x)
#define dprint32(x) print32(x)
#define dprint64(x) print64(x)
#else
#define dprint(x)
#define dprint8(x)
#define dprint16(x)
#define dprint32(x)
#define dprint64(x)
#endif
__attribute__((
used,
section(".limine_requests"))) static volatile struct limine_memmap_request
@ -106,7 +119,7 @@ static void usepage(size_t page) {
}
static void usepagerange(size_t page, size_t len) {
for (size_t i = 0; i < len; len++) {
for (size_t i = 0; i < len; i++) {
usepage(i + page);
}
}
@ -118,7 +131,7 @@ static void unusepage(size_t page) {
}
static void unusepagerange(size_t page, size_t len) {
for (size_t i = 0; i < len; len++) {
for (size_t i = 0; i < len; i++) {
unusepage(i + page);
}
}
@ -144,9 +157,10 @@ void *alloc(size_t size) {
return NULL;
}
print("Attempting to find ");
print64(pages);
print(" consecutive pages\n");
dprint("Attempting to find ");
dprint64(pages);
dprint(" consecutive pages.....");
size_t consecutive = 0;
for (size_t i = 0; i < total_pages / 64; i++) {
@ -157,6 +171,7 @@ void *alloc(size_t size) {
consecutive += 64;
if (consecutive >= pages) {
usepagerange(page, pages);
dprint("succeeded!\n");
return addr(page);
}
continue;
@ -174,6 +189,7 @@ void *alloc(size_t size) {
if (++consecutive >= pages) {
usepagerange(page, pages);
dprint("succeeded!\n");
return addr(page);
}
} else {
@ -183,5 +199,8 @@ void *alloc(size_t size) {
}
}
dprint("failed :(!\n");
return NULL;
}

View File

@ -11,3 +11,4 @@ static inline u64 virt_to_phys(void *virt) { return (u64)virt - hhdm_offset; }
static inline void *phys_to_virt(u64 phys) {
return (void *)(phys + hhdm_offset);
}

View File

@ -72,6 +72,25 @@ char kbd_buffer_getc() {
return c;
}
static u8 held_map[0x100/16];
static void hold_key(u8 key) {
key &= (0x100/2)-1;
held_map[key>>3] |= (1 << (key & 7));
}
static void release_key(u8 key) {
key &= (0x100/2)-1;
held_map[key>>3] &= ~(1 << (key & 7));
}
static bool key_held(u8 key) {
key &= (0x100/2)-1;
return (held_map[key>>3] & (1 << (key & 7)));
}
void kbd_handler() {
u8 scancode = inb(PS2_DATA_PORT);
bool released = (scancode & 0x80);
@ -91,6 +110,7 @@ void kbd_handler() {
if(!released) {
kbd_state.caps = !kbd_state.caps;
}
break;
default:
break;
}
@ -106,18 +126,29 @@ void kbd_handler() {
if(kbd_state.caps && c >= 'a' && c <= 'z') {
c = c - 'a' + 'A';
} else if(kbd_state.caps && c >= 'A' && c <= 'Z') {
c = c - 'A' + 'a';
}
if(c != 0) {
if(c != 0 && !key_held(scancode)) {
kbd_buffer_putc(c);
}
printn(&c, 1);
hold_key(scancode);
} else {
release_key(scancode);
}
send_eoi();
}
int kbd_getc_blocking() {
int ch;
while(!(ch =kbd_buffer_getc()))
;
return ch;
}

View File

@ -1,2 +1,4 @@
#pragma once
void kbd_handler();
int kbd_getc_blocking();
char kbd_buffer_getc();

33
src/lib/malloc.c Normal file
View File

@ -0,0 +1,33 @@
#include <stddef.h>
#include "../alloc.h"
struct malloc_header {
size_t size;
};
void* malloc(size_t sz) {
size_t total = sz + sizeof(struct malloc_header);
struct malloc_header* mh = alloc(total);
if(!mh)
return mh;
mh->size = total;
return (void*)(&mh[1]);
}
void* calloc(size_t sz, size_t n) {
// for now ignore the case of sz * n > 1 << 64
size_t N = sz * n;
u8* ptr = malloc(N);
for(size_t i = 0; i < N; i++)
ptr[i] = 0;
}
void free(void* ptr) {
if(!ptr) {
return;
}
size_t sz = ((struct malloc_header*)ptr)[-1].size;
dealloc(ptr, sz);
}

5
src/lib/malloc.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
void* malloc(size_t sz);
void* calloc(size_t sz, size_t n);
void* free(void* ptr);

475
src/lib/stdio.h Normal file
View File

@ -0,0 +1,475 @@
#pragma once
#include <stdarg.h>
#include "malloc.h"
#include "../common.h"
#include "../kbd.h"
#include "../print.h"
#define MAX_LINE_LEN 256
static inline int puts(const char *s) {
print(s);
put('\n');
return 0;
}
#define _STDIO_PEEK_BUFF_EMPTY -1
static int _stdio_peek_buf = _STDIO_PEEK_BUFF_EMPTY;
/* getc blocking, consumes one character */
static inline int getc(void) {
if (_stdio_peek_buf >= 0) {
int c = _stdio_peek_buf;
_stdio_peek_buf = -1;
return c;
}
return kbd_getc_blocking();
}
/* peek blocking, returns next char WITHOUT consuming it */
static inline int peek(void) {
if (_stdio_peek_buf < 0)
_stdio_peek_buf = kbd_getc_blocking();
return _stdio_peek_buf;
}
/* getc_nb non-blocking version; returns -1 if no char ready */
static inline int getc_nb(void) {
if (_stdio_peek_buf >= 0) {
int c = _stdio_peek_buf;
_stdio_peek_buf = _STDIO_PEEK_BUFF_EMPTY;
return c;
}
int c = kbd_buffer_getc();
return c ? c : _STDIO_PEEK_BUFF_EMPTY;
}
/* peek_nb non-blocking peek; returns -1 if no char ready */
static inline int peek_nb(void) {
if (_stdio_peek_buf < 0) {
int c = kbd_buffer_getc();
if (!c) return -1;
_stdio_peek_buf = c;
}
return _stdio_peek_buf;
}
static inline char *getline_alloc(size_t max_hint) {
size_t cap = max_hint > 0 ? max_hint : 128;
char *buf = (char *)malloc(cap);
if (!buf) {
print("getline_alloc failed to alloc! :(\n");
return NULL;
}
size_t len = 0;
for (;;) {
int c = getc();
if (c == '\b') { /* backspace */
if (len > 0) {
len--;
unput();
}
continue;
}
/* grow buffer if needed (leave room for NUL) */
if (len + 1 >= cap) {
size_t new_cap = cap * 2;
char *new_buf = (char *)malloc(new_cap);
if (!new_buf) { free(buf); print("getline_alloc failed to alloc! :(\n"); return NULL; }
for (size_t i = 0; i < len; i++) new_buf[i] = buf[i];
free(buf);
buf = new_buf;
cap = new_cap;
}
buf[len++] = (char)c;
if (c == '\n' || c == '\r') {
put('\n');
break;
} else {
put(c); /* echo */
}
}
buf[len] = '\0';
return buf;
}
static inline int getline_buf(char *buf, size_t n) {
if (!buf || n == 0) return -1;
size_t len = 0;
for (;;) {
int c = getc();
if (c == '\n' || c == '\r') {
put('\n');
break;
}
if (c == '\b') {
if (len > 0) { len--; unput(); }
continue;
}
if (len < n - 1) {
buf[len++] = (char)c;
put(c);
}
/* else: buffer full keep echoing but discard */
}
buf[len] = '\0';
return (int)len;
}
static inline char *_fmt_uint(char *end, u64 val, int base, bool upper) {
static const char lo[] = "0123456789abcdef";
static const char up[] = "0123456789ABCDEF";
const char *digs = upper ? up : lo;
*--end = '\0';
if (val == 0) { *--end = '0'; return end; }
while (val) { *--end = digs[val % (u64)base]; val /= (u64)base; }
return end;
}
static inline int vprintf(const char *fmt, va_list ap) {
int written = 0;
#define _EMIT(c) do { put(c); written++; } while(0)
#define _EMITS(s) do { const char *_p=(s); while(*_p){_EMIT(*_p);_p++;} } while(0)
while (*fmt) {
if (*fmt != '%') { _EMIT(*fmt++); continue; }
fmt++; /* skip '%' */
/* flags */
bool left_align = false;
bool zero_pad = false;
if (*fmt == '-') { left_align = true; fmt++; }
if (*fmt == '0') { zero_pad = true; fmt++; }
/* width */
int width = 0;
while (*fmt >= '0' && *fmt <= '9') width = width*10 + (*fmt++ - '0');
/* length modifier */
int lng = 0; /* 0=int, 1=long, 2=long long */
if (*fmt == 'l') { lng=1; fmt++; }
if (*fmt == 'l') { lng=2; fmt++; }
char tmp[66];
char *s = NULL;
char cbuf[2] = {0,0};
bool neg = false;
switch (*fmt++) {
case '%':
_EMIT('%');
continue;
case 'c':
cbuf[0] = (char)va_arg(ap, int);
s = cbuf;
break;
case 's':
s = va_arg(ap, char *);
if (!s) s = "(null)";
break;
case 'd': case 'i': {
i64 v = (lng==2) ? va_arg(ap,long long) :
(lng==1) ? va_arg(ap,long) :
va_arg(ap,int);
if (v < 0) { neg = true; v = -v; }
s = _fmt_uint(tmp+65, (u64)v, 10, false);
break;
}
case 'u': {
u64 v = (lng==2) ? va_arg(ap,unsigned long long) :
(lng==1) ? va_arg(ap,unsigned long) :
va_arg(ap,unsigned int);
s = _fmt_uint(tmp+65, v, 10, false);
break;
}
case 'o': {
u64 v = (lng==2) ? va_arg(ap,unsigned long long) :
(lng==1) ? va_arg(ap,unsigned long) :
va_arg(ap,unsigned int);
s = _fmt_uint(tmp+65, v, 8, false);
break;
}
case 'x': {
u64 v = (lng==2) ? va_arg(ap,unsigned long long) :
(lng==1) ? va_arg(ap,unsigned long) :
va_arg(ap,unsigned int);
s = _fmt_uint(tmp+65, v, 16, false);
break;
}
case 'X': {
u64 v = (lng==2) ? va_arg(ap,unsigned long long) :
(lng==1) ? va_arg(ap,unsigned long) :
va_arg(ap,unsigned int);
s = _fmt_uint(tmp+65, v, 16, true);
break;
}
case 'p': {
u64 v = (u64)(uintptr_t)va_arg(ap, void *);
print("0x");
written += 2;
s = _fmt_uint(tmp+65, v, 16, false);
break;
}
default:
_EMIT('?');
continue;
}
/* padding / output */
int slen = 0;
for (const char *p = s; *p; p++) slen++;
if (neg) slen++; /* for '-' */
int pad = width - slen;
if (!left_align && pad > 0) {
char pc = zero_pad ? '0' : ' ';
if (neg && zero_pad) { _EMIT('-'); neg=false; written++; }
while (pad-- > 0) { _EMIT(pc); written++; }
}
if (neg) { _EMIT('-'); written++; }
while (*s) { _EMIT(*s++); written++; }
if (left_align && pad > 0)
while (pad-- > 0) { _EMIT(' '); written++; }
}
#undef _EMIT
#undef _EMITS
return written;
}
static inline int printf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int r = vprintf(fmt, ap);
va_end(ap);
return r;
}
typedef struct { char *p; size_t rem; } _sbuf;
/* We re-implement the inner loop targeting a string buffer instead of the
* screen. Factoring out a shared back-end with a function pointer would be
* cleaner but adds complexity; this keeps it self-contained. */
static inline int vsnprintf(char *out, size_t size, const char *fmt, va_list ap) {
if (!out || !size) return 0;
char *cur = out;
char *end = out + size - 1; /* leave room for NUL */
int written = 0;
#define _SEMIT(c) do { if(cur<end){*cur++=(char)(c);} written++; } while(0)
while (*fmt) {
if (*fmt != '%') { _SEMIT(*fmt++); continue; }
fmt++;
bool left_align=false, zero_pad=false;
if (*fmt=='-'){left_align=true;fmt++;}
if (*fmt=='0'){zero_pad=true;fmt++;}
int width=0;
while(*fmt>='0'&&*fmt<='9') width=width*10+(*fmt++-'0');
int lng=0;
if(*fmt=='l'){lng=1;fmt++;}
if(*fmt=='l'){lng=2;fmt++;}
char tmp[66];
char *s=NULL;
char cbuf[2]={0,0};
bool neg=false;
switch(*fmt++) {
case '%': _SEMIT('%'); continue;
case 'c': cbuf[0]=(char)va_arg(ap,int); s=cbuf; break;
case 's': s=va_arg(ap,char*); if(!s)s="(null)"; break;
case 'd': case 'i': {
i64 v=(lng==2)?va_arg(ap,long long):(lng==1)?va_arg(ap,long):va_arg(ap,int);
if(v<0){neg=true;v=-v;}
s=_fmt_uint(tmp+65,(u64)v,10,false); break;
}
case 'u': {
u64 v=(lng==2)?va_arg(ap,unsigned long long):(lng==1)?va_arg(ap,unsigned long):va_arg(ap,unsigned int);
s=_fmt_uint(tmp+65,v,10,false); break;
}
case 'o': {
u64 v=(lng==2)?va_arg(ap,unsigned long long):(lng==1)?va_arg(ap,unsigned long):va_arg(ap,unsigned int);
s=_fmt_uint(tmp+65,v,8,false); break;
}
case 'x': {
u64 v=(lng==2)?va_arg(ap,unsigned long long):(lng==1)?va_arg(ap,unsigned long):va_arg(ap,unsigned int);
s=_fmt_uint(tmp+65,v,16,false); break;
}
case 'X': {
u64 v=(lng==2)?va_arg(ap,unsigned long long):(lng==1)?va_arg(ap,unsigned long):va_arg(ap,unsigned int);
s=_fmt_uint(tmp+65,v,16,true); break;
}
case 'p': {
u64 v=(u64)(uintptr_t)va_arg(ap,void*);
_SEMIT('0'); _SEMIT('x'); written+=2;
s=_fmt_uint(tmp+65,v,16,false); break;
}
default: _SEMIT('?'); continue;
}
int slen=0; for(const char*p=s;*p;p++) slen++; if(neg) slen++;
int pad=width-slen;
if(!left_align&&pad>0){char pc=zero_pad?'0':' '; if(neg&&zero_pad){_SEMIT('-');neg=false;} while(pad-->0){_SEMIT(pc);}}
if(neg){_SEMIT('-');}
while(*s){_SEMIT(*s++);}
if(left_align&&pad>0) while(pad-->0){_SEMIT(' ');}
}
#undef _SEMIT
*cur = '\0';
return written;
}
static inline int snprintf(char *out, size_t size, const char *fmt, ...) {
va_list ap; va_start(ap, fmt);
int r = vsnprintf(out, size, fmt, ap);
va_end(ap); return r;
}
static inline int sprintf(char *out, const char *fmt, ...) {
va_list ap; va_start(ap, fmt);
/* pass a huge size caller's responsibility to have enough room */
int r = vsnprintf(out, (size_t)-1, fmt, ap);
va_end(ap); return r;
}
static inline int _skip_ws(const char **p) {
while (**p==' '||**p=='\t'||**p=='\n'||**p=='\r') (*p)++;
return 0;
}
static inline int vsscanf(const char *str, const char *fmt, va_list ap) {
const char *s = str;
int matched = 0;
while (*fmt) {
if (*fmt == ' ') { _skip_ws(&s); fmt++; continue; }
if (*fmt != '%') {
if (*s != *fmt) return matched;
s++; fmt++; continue;
}
fmt++; /* skip '%' */
if (*fmt == '%') { if (*s=='%') s++; fmt++; continue; }
int lng = 0;
if (*fmt=='l'){lng=1;fmt++;}
if (*fmt=='l'){lng=2;fmt++;}
_skip_ws(&s);
switch (*fmt++) {
case 'c': {
char *out = va_arg(ap, char*);
if (!*s) return matched;
*out = *s++;
matched++;
break;
}
case 's': {
char *out = va_arg(ap, char*);
if (!*s) return matched;
while (*s && *s!=' '&&*s!='\t'&&*s!='\n'&&*s!='\r')
*out++ = *s++;
*out = '\0';
matched++;
break;
}
case 'd': case 'i': {
bool neg2 = false;
if (*s=='-'){neg2=true;s++;}
else if(*s=='+') s++;
if (*s<'0'||*s>'9') return matched;
i64 v=0;
while(*s>='0'&&*s<='9') v=v*10+(*s++-'0');
if(neg2) v=-v;
if(lng==2) *va_arg(ap,long long*)=(long long)v;
else if(lng==1) *va_arg(ap,long*)=(long)v;
else *va_arg(ap,int*)=(int)v;
matched++;
break;
}
case 'u': {
if(*s<'0'||*s>'9') return matched;
u64 v=0;
while(*s>='0'&&*s<='9') v=v*10+(*s++-'0');
if(lng==2) *va_arg(ap,unsigned long long*)=(unsigned long long)v;
else if(lng==1) *va_arg(ap,unsigned long*)=(unsigned long)v;
else *va_arg(ap,unsigned int*)=(unsigned int)v;
matched++;
break;
}
case 'x': case 'X': {
if(*s=='0'&&(*(s+1)=='x'||*(s+1)=='X')) s+=2;
u64 v=0; bool any=false;
while((*s>='0'&&*s<='9')||(*s>='a'&&*s<='f')||(*s>='A'&&*s<='F')){
u8 d=(*s>='a')?*s-'a'+10:(*s>='A')?*s-'A'+10:*s-'0';
v=v*16+d; s++; any=true;
}
if(!any) return matched;
if(lng==2) *va_arg(ap,unsigned long long*)=(unsigned long long)v;
else if(lng==1) *va_arg(ap,unsigned long*)=(unsigned long)v;
else *va_arg(ap,unsigned int*)=(unsigned int)v;
matched++;
break;
}
case 'o': {
if(*s<'0'||*s>'7') return matched;
u64 v=0;
while(*s>='0'&&*s<='7') v=v*8+(*s++-'0');
if(lng==2) *va_arg(ap,unsigned long long*)=(unsigned long long)v;
else if(lng==1) *va_arg(ap,unsigned long*)=(unsigned long)v;
else *va_arg(ap,unsigned int*)=(unsigned int)v;
matched++;
break;
}
default:
return matched;
}
}
return matched;
}
static inline int sscanf(const char *str, const char *fmt, ...) {
va_list ap; va_start(ap, fmt);
int r = vsscanf(str, fmt, ap);
va_end(ap); return r;
}
static inline int scanf(const char *fmt, ...) {
char *line = getline_alloc(MAX_LINE_LEN);
if (!line) return -1;
va_list ap; va_start(ap, fmt);
int r = vsscanf(line, fmt, ap);
va_end(ap);
free(line);
return r;
}

View File

@ -12,8 +12,10 @@ void print_tok(struct token* tok);
#include "alloc.h"
#include "apic.h"
#include "common.h"
#include "kbd.h"
#include "map.h"
#include "print.h"
#include "lib/stdio.h"
// credit owed to https://wiki.osdev.org/Limine_Bare_Bones for the limine setup
// code
@ -110,7 +112,8 @@ void draw(u8 vect) {
for (size_t y = 0; y < fb->height; y++) {
for (size_t x = 0; x < fb->width; x++) {
volatile u32 *fb_ptr = fb->address;
fb_ptr[y * fb->width + x] = (((x ^ y) & 0xff) * 0x0F0003) * vect;
int tone = ((x ^ y) & 0xFF) >> 6;
fb_ptr[y * fb->width + x] = (tone << 16);
}
}
}
@ -153,8 +156,8 @@ void kmain() {
draw(1);
print_init(fb);
init_idt();
bg = 0xFFFFFF;
fg = 0x000000;
fg = 0xFFFFFF;
bg = 0x000000;
if (!hhdm_req.response) {
print("Failed to get higher half direct mapping\n.");
@ -197,19 +200,30 @@ void kmain() {
apic_enable();
print("APIC Enabled\n");
ioapic_init();
const char* src[] = {
"u8 main(u32 x) {\n",
" u16 y = x + 16;\n",
" u8 z = x * y;\n",
" return z; }\n"
};
const char* name = "prompt> ";
asm volatile("sti");
#define LINES 40
size_t max_len = MAX_LINE_LEN;
char* line = getline_alloc(max_len);
char* lines[LINES];
size_t n_lines = 0;
for(n_lines = 0; n_lines < LINES; n_lines++) {
line = getline_alloc(max_len);
if(!line)
break;
if(line[0] == 'F' && line[1] == 'I' && line[2] == '\n')
break;
lines[n_lines] = line;
}
const char* name = "stdin";
struct file input = {
.row = 0,
.col = 0,
.rows = 4,
.lines = (char**)src,
.rows = n_lines,
.lines = (char**)lines,
.name = name,
.tokens = NULL,
.tail = &input.tokens,
@ -217,21 +231,15 @@ void kmain() {
int res = lex(&input);
print("Result from lexing: ");
print("Number of Errors: ");
print8(res);
if(res != 0) {
hang();
}
printf("\n# of Tokens: %d\n", input.tokens->len);
struct token* token = input.tokens;
for(;token; token = token->next) {
print_tok(token);
}
asm volatile("sti");
hang();
}

View File

@ -14,20 +14,24 @@ static volatile u32 *fb_scr;
#define TAB_STOP 4
// buffer at each edge for readability
#define TERM_WIDTH (FONT_WIDTH + 2)
#define TERM_HEIGHT (FONT_HEIGHT + 2)
#define GLYPH_WIDTH (FONT_WIDTH + 2)
#define GLYPH_HEIGHT (FONT_HEIGHT + 2)
void print_init(struct limine_framebuffer *fb) {
term_width = fb->width / TERM_WIDTH;
term_height = fb->height / TERM_HEIGHT;
term_width = fb->width / GLYPH_WIDTH;
term_height = fb->height / GLYPH_HEIGHT;
fb_width = fb->width;
fb_height = fb->height;
fb_scr = fb->address;
}
static void scrollback() {
memmove((void *)fb_scr, (void *)(fb_scr + fb_width * TERM_HEIGHT),
fb_width * (fb_height - TERM_HEIGHT) * sizeof(u32));
memmove((void *)fb_scr, (void *)(fb_scr + fb_width * GLYPH_HEIGHT),
fb_width * (fb_height - GLYPH_HEIGHT) * sizeof(u32));
size_t last_row_start = (term_height - 1) * fb_width;
for (size_t i = 0; i < fb_width; i++) {
fb_scr[last_row_start + i] = bg;
}
}
void put(int ch) {
@ -63,14 +67,14 @@ void put(int ch) {
size_t idx = ch - ' ';
u32 glyph = font[idx];
size_t px = col * TERM_WIDTH;
size_t py = row * TERM_HEIGHT;
size_t px = col * GLYPH_WIDTH;
size_t py = row * GLYPH_HEIGHT;
for (size_t y = 0; y < TERM_HEIGHT; y++) {
for (size_t x = 0; x < TERM_WIDTH; x++) {
for (size_t y = 0; y < GLYPH_HEIGHT; y++) {
for (size_t x = 0; x < GLYPH_WIDTH; x++) {
size_t off = (py + y) * fb_width + (px + x);
bool padding =
(y == 0 || y == TERM_HEIGHT - 1 || x == 0 || x == TERM_WIDTH - 1);
(y == 0 || y == GLYPH_HEIGHT - 1 || x == 0 || x == GLYPH_WIDTH - 1);
fb_scr[off] = ((~glyph & 1) | padding) ? bg : fg;
glyph >>= !padding;
}
@ -112,3 +116,20 @@ void print64(u64 n) {
print32(n >> 32);
print32(n & 0xFFFFFFFF);
}
void unput(void) {
if (col > 0) {
col--;
} else if (row > 0) {
row--;
col = term_width - 1;
} else {
return; /* already at (0,0), nothing to erase */
}
size_t px = col * GLYPH_WIDTH;
size_t py = row * GLYPH_HEIGHT;
for (size_t y = 0; y < GLYPH_HEIGHT; y++)
for (size_t x = 0; x < GLYPH_WIDTH; x++)
fb_scr[(py + y) * fb_width + (px + x)] = bg;
}

View File

@ -13,3 +13,4 @@ void print32(u32 n);
void print16(u16 n);
void print8(u8 n);
void print_init(struct limine_framebuffer *fb);
void unput(void);

View File

@ -6,8 +6,11 @@
static int lex_error(struct file* state, const char* err) {
print(state->name);
print("[");
print16(state->row+1);
print(":");
print16(state->col+1);
print("] ");
print(err);
print("\n");
return 1;
@ -74,14 +77,12 @@ static struct token* tok(enum tokentype type, struct file* state, int col, void*
return ret;
}
static bool isdigit(int ch) {
return (ch <= '9' && ch >= '0');
}
static bool isxdigit(int ch) {
return ((ch <= '9' && ch >= '0') || (ch <= 'F' && ch >= 'A') || (ch <= 'F' && ch >= 'A'));
}
static bool isalpha(int ch) {
return (ch <= 'z' && ch >= 'a')
|| (ch <= 'Z' && ch >= 'A');
@ -103,6 +104,10 @@ static int tolower(int ch) {
return ch;
}
static bool isxdigit(int ch) {
return isdigit(ch) || (isalpha(ch) && tolower(ch) <= 'f');
}
// cribbed from musl
static bool isspace(int ch) {
return ch == ' ' || (unsigned)ch-'\t' < 5;
@ -113,7 +118,10 @@ static int parse_num(struct file* state, int save, int sign) {
int ch = state->lines[state->row][state->col];
if(ch == '0' && state->lines[state->row][state->col+1] == 'x') {
state->col+=2;
if(!isdigit(state->lines[state->row][state->col])) {
if(!isxdigit(state->lines[state->row][state->col])) {
print("On input: '");
printn(&state->lines[state->row][state->col], 1);
print("'\n");
lex_error(state, "expected hexadecimal digits in hex literal");
return 1;
}
@ -155,7 +163,7 @@ int lex(struct file* state) {
if(state->row >= state->rows)
return 0;
while(isspace(state->lines[state->row][state->col])) {
if(state->lines[state->row][state->col] == '\n') {
if(state->lines[state->row][state->col] == '\n' || !state->lines[state->row][state->col]) {
state->col = 0;
state->row++;
if(state->row >= state->rows)
@ -168,7 +176,7 @@ int lex(struct file* state) {
if(state->lines[state->row][state->col] == '/' && state->lines[state->row][state->col+1] == '*') {
state->col += 2;
while(!(state->lines[state->row][state->col] == '*' && state->lines[state->row][state->col+1] == '/')) {
if(state->lines[state->row][state->col] == '\n') {
if(state->lines[state->row][state->col] == '\n' || !state->lines[state->row][state->col]) {
state->col = -1;
state->row++;
if(state->row >= state->rows)
@ -177,7 +185,7 @@ int lex(struct file* state) {
state->col++;
}
state->col += 2;
if(state->lines[state->row][state->col] == '\n') {
if(state->lines[state->row][state->col] == '\n' || !state->lines[state->row][state->col]) {
state->row++;
state->col = 0;
}
@ -240,7 +248,7 @@ int lex(struct file* state) {
print8(ch);
print(") '");
printn(&ch,1);
print("\n");
print("'\n");
state->col++;
return 1 + lex(state);
}

View File

@ -14,6 +14,7 @@ static size_t strlen(const char* str) {
extern u32 fg, bg;
void print_tok(struct token* tok) {
u32 savebg = bg, savefg = fg;
/* header: [file:row:col] */
print("[");
print(tok->file->name);
@ -29,24 +30,28 @@ void print_tok(struct token* tok) {
}
print("] ");
u32 color = fg;
switch (tok->type) {
case TOK_KEYWORD:
color = 0xFF3322;
print("keyword: ");
print(keywords[tok->keyword]);
print("\n");
break;
case TOK_NUM:
color = 0x3322FF;
print("number: ");
print(" (");
print64((unsigned long)tok->num);
print("):\n");
break;
case TOK_IDEN: {
color = 0x137FFF;
struct iden* id = &identbl[tok->iden];
print("iden: { .hash = 0x");
print32(id->hash);
print(", .data = \"");
print(*id->data);
print(id->data);
print("\" (");
/* print pointer value as hex */
print("ptr"); /* pointer printing omitted; add if needed */
@ -56,6 +61,7 @@ void print_tok(struct token* tok) {
break;
}
case TOK_OP: {
color = 0xBEDEAD;
print("operator: ");
print(ops[tok->op]);
print(" (#");
@ -64,6 +70,7 @@ void print_tok(struct token* tok) {
break;
}
default: {
color = 0x00FF00;
/* print single char and hex */
char c[2] = { (char)tok->type, 0 };
print(c);
@ -108,13 +115,15 @@ void print_tok(struct token* tok) {
printn(tok->file->lines[tok->row], tok->col);
/* print token text */
fg = color;
if (tok->len > 0)
printn(tok->file->lines[tok->row] + tok->col, tok->len);
fg = savefg;
bg = savebg;
/* print rest of line after token */
printn(tok->file->lines[tok->row] + tok->col + tok->len,
strlen(tok->file->lines[tok->row] + tok->col + tok->len));
print("\n");
/* caret line */
print("\t | ");
@ -125,7 +134,7 @@ void print_tok(struct token* tok) {
print(" ");
}
}
u32 savebg = bg, savefg = fg;
fg = bg;
bg = ~fg;
print("^");