diff --git a/Makefile b/Makefile index 9786cda..ff14510 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,20 @@ -SRCS = $(shell find -name '*.[cS]') +SRCS = $(shell find . -regextype posix-egrep -regex '.*\.[cS]') src/cplusplus.cpp OBJS = $(addsuffix .o,$(basename $(SRCS))) CC = gcc +CXX = g++ LD = ld +LEX=flex +YACC=bison # define nullptr, but not NULL. CFLAGS = -m32 -Dnullptr=0 ASFLAGS = -CCFLAGS = -g -std=c11 -Wall -g -fno-stack-protector -ffreestanding +CCFLAGS = -g -std=c11 -Wall -g -fno-stack-protector -ffreestanding -Iinclude +CXXFLAGS = -g -std=c++11 -Wall -g -fno-stack-protector -fno-exceptions -ffreestanding -Wno-unused-function -Iinclude LDFLAGS = -g -melf_i386 -Tkernel.ld -kernel: $(OBJS) +kernel: $(OBJS) obj/tsvm.o obj/lex.yy.o obj/trainscript.tab.o $(LD) $(LDFLAGS) -o $@ $(addprefix obj/, $(notdir $^)) %.o: %.c @@ -19,6 +23,24 @@ kernel: $(OBJS) %.o: %.S $(CC) $(CFLAGS) $(ASFLAGS) -c -o $(addprefix obj/, $(notdir $@)) $^ +%.o: %.cpp + $(CXX) $(CFLAGS) $(CXXFLAGS) -c -o $(addprefix obj/, $(notdir $@)) $^ + +obj/tsvm.o: trainscript/tsvm.cpp trainscript/tsvm.hpp trainscript/common.h + g++ $(CFLAGS) $(CXXFLAGS) -c trainscript/tsvm.cpp -o obj/tsvm.o + +obj/lex.yy.o: trainscript/lex.yy.cpp trainscript/tsvm.hpp trainscript/common.h trainscript/trainscript.tab.cpp + g++ $(CFLAGS) $(CXXFLAGS) -c trainscript/lex.yy.cpp -o obj/lex.yy.o + +trainscript.tab.o: trainscript/lex.yy.cpp trainscript/trainscript.tab.cpp trainscript/tsvm.hpp trainscript/common.h + g++ $(CFLAGS) $(CXXFLAGS) -c trainscript/trainscript.tab.cpp -o obj/trainscript.tab.o + +trainscript/lex.yy.cpp: trainscript/trainscript.l + $(LEX) --header-file=trainscript/trainscript.l.h -o trainscript/lex.yy.cpp trainscript/trainscript.l + +trainscript/trainscript.tab.cpp: trainscript/trainscript.y + $(YACC) -o trainscript/trainscript.tab.cpp -d trainscript/trainscript.y + clean: rm $(addprefix obj/, $(notdir $(OBJS))) diff --git a/src/console.h b/include/console.h similarity index 93% rename from src/console.h rename to include/console.h index 2496df2..199a5c6 100644 --- a/src/console.h +++ b/include/console.h @@ -1,5 +1,9 @@ #pragma once +#if defined(__cplusplus) +extern "C" { +#endif + #define CONSOLE_WIDTH 80 #define CONSOLE_HEIGHT 25 @@ -71,4 +75,8 @@ void kputs(const char *str); * @param format The format string that will be printed in formatted version. * @param ... The format parameters that will be used to print the string. */ -void kprintf(const char *format, ...); \ No newline at end of file +void kprintf(const char *format, ...); + +#if defined(__cplusplus) +} +#endif diff --git a/src/cpustate.h b/include/cpustate.h similarity index 80% rename from src/cpustate.h rename to include/cpustate.h index 20acaa3..4f644b8 100644 --- a/src/cpustate.h +++ b/include/cpustate.h @@ -1,6 +1,10 @@ #pragma once #include "inttypes.h" +#if defined(__cplusplus) +extern "C" { +#endif + typedef struct { // Saved by interrupt routine @@ -21,4 +25,8 @@ typedef struct uint32_t eflags; uint32_t esp; uint32_t ss; -} CpuState; \ No newline at end of file +} CpuState; + +#if defined(__cplusplus) +} +#endif diff --git a/src/interrupts.h b/include/interrupts.h similarity index 62% rename from src/interrupts.h rename to include/interrupts.h index 4d81174..3b85ec8 100644 --- a/src/interrupts.h +++ b/include/interrupts.h @@ -1,4 +1,9 @@ #pragma once +#include "cpustate.h" + +#if defined(__cplusplus) +extern "C" { +#endif #define GDTF_DATASEG 0x02 #define GDTF_CODESEG 0x0a @@ -16,11 +21,20 @@ #define INTR_TRAP_GATE 7 #define INTR_TASK_GATE 5 +typedef void (*InterruptHandler)(CpuState *); + /** * Initializes interrupt handling and the global descriptor table. */ void intr_init(); +/** + * @brief Sets the handler for the given interrupt. + * @param interrupt The number of the interrupt. + * @param handler The function that should handle this interrupt + */ +void intr_set_handler(uint32_t interrupt, InterruptHandler handler); + /** * @brief Enables physical interrupts. */ @@ -37,3 +51,6 @@ static inline void irq_disable(void) __asm__ volatile("cli"); } +#if defined(__cplusplus) +} +#endif diff --git a/src/io.h b/include/io.h similarity index 70% rename from src/io.h rename to include/io.h index 70e8901..ab9dec6 100644 --- a/src/io.h +++ b/include/io.h @@ -1,6 +1,11 @@ #pragma once -#include "inttypes.h" +#include + +#if defined(__cplusplus) +extern "C" { +#endif + /** * @brief Outputs a byte on the given port. @@ -11,3 +16,7 @@ static inline void outb(uint16_t port, uint8_t data) { __asm__ volatile ("outb %0, %1" : : "a" (data), "Nd" (port)); } + +#if defined(__cplusplus) +} +#endif diff --git a/include/ker/dictionary.hpp b/include/ker/dictionary.hpp new file mode 100644 index 0000000..fecbf77 --- /dev/null +++ b/include/ker/dictionary.hpp @@ -0,0 +1,98 @@ +#pragma once + +#include "pair.hpp" +#include "vector.hpp" + +namespace ker +{ + template + class Dictionary + { + public: + typedef Pair Entry; + private: + Vector contents; + public: + Dictionary() : + contents() + { + + } + + Value &at(const Key &key) + { + for(auto &&pair : this->contents) + { + if(pair.first == key) { + return pair.second; + } + } + } + + const Value &at(const Key &key) const + { + for(auto &&pair : this->contents) + { + if(pair.first == key) { + return pair.second; + } + } + } + + bool contains(const Key &key) const + { + for(const auto &pair : this->contents) + { + if(pair.first == key) { + return true; + } + } + return false; + } + + void add(const Key &key, const Value &value) + { + if(this->contains(key)) { + for(auto &&pair : this->contents) + { + if(pair.first == key) { + pair.second = value; + return; + } + } + } else { + this->contents.append(Entry(key, value)); + } + } + + Value& operator [](const Key &key) + { + return this->at(key); + } + + const Value& operator [](const Key &key) const + { + return this->at(key); + } + + Entry * begin() + { + return this->contents.begin(); + } + + Entry * end() + { + return this->contents.end(); + } + + const Entry * begin() const + { + return this->contents.begin(); + } + + const Entry * end() const + { + return this->contents.end(); + } + }; +} diff --git a/include/ker/new.hpp b/include/ker/new.hpp new file mode 100644 index 0000000..36f3756 --- /dev/null +++ b/include/ker/new.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +inline void* operator new(size_t size, void* __p) +{ + return __p; +} + +inline void* operator new[](size_t size, void* __p) +{ + return __p; +} + +inline void operator delete (void*, void*) { } +inline void operator delete[](void*, void*) { } diff --git a/include/ker/pair.hpp b/include/ker/pair.hpp new file mode 100644 index 0000000..369d493 --- /dev/null +++ b/include/ker/pair.hpp @@ -0,0 +1,20 @@ +#pragma once + +namespace ker +{ + template + struct Pair + { + First first; + Second second; + + Pair() : first(), second() { } + + Pair(const First &first, const Second &second) : + first(first), + second(second) + { + + } + }; +} diff --git a/include/ker/string.hpp b/include/ker/string.hpp new file mode 100644 index 0000000..72061d5 --- /dev/null +++ b/include/ker/string.hpp @@ -0,0 +1,100 @@ +#pragma once + +#include +#include + +namespace ker +{ + class String + { + private: + uint8_t *mText; + size_t mLength; + public: + String() : + mText(nullptr), + mLength(0) + { + + } + + String(const char *text) : + mText(nullptr), + mLength(0) + { + this->mLength = strlen(text); + this->mText = (uint8_t*)malloc(this->mLength + 1); + memcpy(this->mText, text, this->mLength); + } + + String(const uint8_t *bytes, size_t length) : + mText((uint8_t*)malloc(length)), + mLength(length) + { + memcpy(this->mText, bytes, length); + } + + ~String() + { + free(this->mText); + } + + size_t length() const + { + return this->mLength; + } + + bool equals(const String &other) const + { + if(this->mLength != other.mLength) { + return false; + } + return memcmp(this->mText, other.mText, this->mLength) != 0; + } + + const uint8_t *text() const + { + static const uint8_t empty[] = { 0 }; + if(this->mText != nullptr) { + return this->mText; + } else { + return empty; + } + } + + const char *str() const + { + return (char*)this->text(); + } + + operator const uint8_t *() const + { + return this->text(); + } + + operator const char *() const + { + return this->str(); + } + + uint8_t & operator [](size_t index) + { + return this->mText[index]; + } + + const uint8_t & operator [](size_t index) const + { + return this->mText[index]; + } + + bool operator ==(const String &other) const + { + return this->equals(other); + } + + bool operator !=(const String &other) const + { + return !this->equals(other); + } + }; +}; diff --git a/include/ker/vector.hpp b/include/ker/vector.hpp new file mode 100644 index 0000000..6dc11c1 --- /dev/null +++ b/include/ker/vector.hpp @@ -0,0 +1,117 @@ +#pragma once + +#include +#include "new.hpp" + +namespace ker +{ + template + class Vector + { + public: + static const size_t initialCap = 32; + private: + T *mData; + size_t mLength; + size_t mReserved; + public: + Vector() : + mData(nullptr), + mLength(0), + mReserved(0) + { + this->reserve(Vector::initialCap); + } + + explicit Vector(size_t initialReserve) : + Vector() + { + this->reserve(initialReserve); + } + + size_t length() const + { + return this->mLength; + } + + T &at(size_t index) + { + return this->mData[index]; + } + + const T &at(size_t index) const + { + return this->mData[index]; + } + + void append(const T &value) + { + this->reserve(this->mLength + 1); + new (&this->mData[this->mLength - 1]) T(value); + this->mLength += 1; + } + + void resize(size_t size) + { + size_t current = this->mLength; + this->reserve(size); + + if(current > size) { + // "Downgrade" + for(size_t i = this->mLength - 1; i > size; i--) { + this->mData[i].~T(); + } + } else { + // "Upgrade" + for(size_t i = this->mLength; i < size; i++) { + new (&this->mData[i]) T (); + } + } + } + + void reserve(size_t space) + { + if(this->mReserved >= space) { + return; + } + const size_t newSize = sizeof(T) * space; + + T *newData = (T*)malloc(newSize); + if(this->mData != nullptr) { + memcpy(newData, this->mData, newSize); + free(this->mData); + } + this->mData = newData; + } + + T& operator [](size_t idx) + { + return this->at(idx); + } + + const T& operator [](size_t idx) const + { + return this->at(idx); + } + + T* begin() + { + return &this->mData[0]; + } + + T* end() + { + return &this->mData[this->mLength]; + } + + const T* begin() const + { + return &this->mData[0]; + } + + const T* end() const + { + return &this->mData[this->mLength]; + } + }; +} diff --git a/include/kernel.h b/include/kernel.h new file mode 100644 index 0000000..200da0d --- /dev/null +++ b/include/kernel.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +void die(const char *msg); + +#if defined(__cplusplus) +} +#endif diff --git a/src/multiboot.h b/include/multiboot.h similarity index 96% rename from src/multiboot.h rename to include/multiboot.h index 425396d..d14fe64 100644 --- a/src/multiboot.h +++ b/include/multiboot.h @@ -2,6 +2,10 @@ #include +#if defined(__cplusplus) +extern "C" { +#endif + #define MB_MEMSIZE (1<<0) #define MB_BOOTDEVICE (1<<1) #define MB_COMMANDLINE (1<<2) @@ -89,3 +93,7 @@ typedef struct { uint16_t vbeInterfaceOffset; uint16_t vbeInterfaceLength; } __attribute__((packed)) MultibootStructure; + +#if defined(__cplusplus) +} +#endif diff --git a/src/pmm.h b/include/pmm.h similarity index 84% rename from src/pmm.h rename to include/pmm.h index d356121..172e508 100644 --- a/src/pmm.h +++ b/include/pmm.h @@ -2,6 +2,10 @@ #include "multiboot.h" +#if defined(__cplusplus) +extern "C" { +#endif + /** * Initializes physical memory management. * @param mb The multi boot structure used for gathering information about free memory. @@ -22,3 +26,7 @@ void *pmm_alloc(void); * Calculates the free memory in bytes. */ uint32_t pmm_calc_free(void); + +#if defined(__cplusplus) +} +#endif diff --git a/src/stdlib.h b/include/stdlib.h similarity index 72% rename from src/stdlib.h rename to include/stdlib.h index b85d2fa..3cb54c7 100644 --- a/src/stdlib.h +++ b/include/stdlib.h @@ -4,6 +4,10 @@ #include #include "varargs.h" +#if defined(__cplusplus) +extern "C" { +#endif + char *itoa(int value, char *str, int base); int atoi(const char *str); float atof(const char *str); @@ -21,6 +25,10 @@ void *malloc(size_t size); */ void free(void *mem); +void* realloc (void* ptr, size_t size); + +void exit(int errorCode); + static inline void *memset(void *ptr, int value, size_t num) { uint8_t *it = (uint8_t*)ptr; @@ -44,6 +52,20 @@ static inline void *memcpy(void *destination, const void *source, size_t num) void *memmove(void *destination, const void *source, size_t num); +static inline int memcmp(const void *s1, const void *s2, size_t n) +{ + const uint8_t * p1 = (const uint8_t *)s1; + const uint8_t * p2 = (const uint8_t *)s2; + for ( ; n-- ; p1++, p2++) { + uint8_t u1 = *p1; + uint8_t u2 = *p2; + if ( u1 != u2) { + return (u1-u2); + } + } + return 0; +} + static inline char *strcpy(char *destination, const char *source) { while(*source) @@ -79,3 +101,15 @@ static inline void *calloc(size_t size) memset(mem, 0, size); return mem; } + +static inline char * strdup(const char *str) +{ + size_t len = strlen(str) + 1; + char * n = (char*)malloc(len); + memcpy(n, str, len); + return n; +} + +#if defined(__cplusplus) +} +#endif diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..08e1311 --- /dev/null +++ b/include/string.h @@ -0,0 +1,3 @@ +#pragma once + +#include "stdlib.h" diff --git a/include/timer.h b/include/timer.h new file mode 100644 index 0000000..af53d48 --- /dev/null +++ b/include/timer.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * @brief Initializes the hardware timer. + */ +void timer_init(); + +/** + * @brief Gets the number of ticks the timer has ticked. + * @return + */ +uint64_t timer_get(); + +/** + * @brief Sets the timer to a given value. + * @param time The number of ticks the timer should have now. + */ +void timer_set(uint64_t time); + + +/** + * @brief Waits until a certain time elapsed. + * @param ticks The number of ticks to wait + */ +void sleep(uint64_t ticks); + +#if defined(__cplusplus) +} +#endif diff --git a/src/varargs.h b/include/varargs.h similarity index 56% rename from src/varargs.h rename to include/varargs.h index 9aac995..1e20a93 100644 --- a/src/varargs.h +++ b/include/varargs.h @@ -1,6 +1,14 @@ #pragma once +#if defined(__cplusplus) +extern "C" { +#endif + typedef __builtin_va_list va_list; #define va_start(ap, X) __builtin_va_start(ap, X) #define va_arg(ap, type) __builtin_va_arg(ap, type) -#define va_end(ap) __builtin_va_end(ap) \ No newline at end of file +#define va_end(ap) __builtin_va_end(ap) + +#if defined(__cplusplus) +} +#endif diff --git a/src/vmm.h b/include/vmm.h similarity index 87% rename from src/vmm.h rename to include/vmm.h index 4190cbf..de4299d 100644 --- a/src/vmm.h +++ b/include/vmm.h @@ -2,6 +2,10 @@ #include +#if defined(__cplusplus) +extern "C" { +#endif + #define VM_PRESENT 0x01 #define VM_WRITABLE 0x02 #define VM_USER 0x04 @@ -19,3 +23,7 @@ void vmm_init(void); * @remarks If flags is 0, the mapping will be undone. */ void vmm_map(uintptr_t virtual, uintptr_t physical, uint32_t flags); + +#if defined(__cplusplus) +} +#endif diff --git a/src/cplusplus.cpp b/src/cplusplus.cpp new file mode 100644 index 0000000..d0ad01e --- /dev/null +++ b/src/cplusplus.cpp @@ -0,0 +1,24 @@ + +#include +#include +#include + +void *operator new( size_t size ) +{ + return calloc( size ); +} + +void *operator new[]( size_t size ) +{ + return calloc( size ); +} + +void operator delete( void *obj ) +{ + free( obj ); +} + +void operator delete[]( void *obj ) +{ + free( obj ); +} diff --git a/src/init.c b/src/init.c index 437d5e6..156e268 100644 --- a/src/init.c +++ b/src/init.c @@ -1,9 +1,11 @@ -#include "kernel.h" -#include "stdlib.h" -#include "console.h" -#include "interrupts.h" -#include "pmm.h" -#include "vmm.h" +#include +#include +#include +#include +#include +#include + +#include void die(const char *msg) { @@ -16,15 +18,6 @@ void die(const char *msg) } } -void ksleep(uint32_t time) -{ - for(uint32_t i = 0; i < time; i++) - { - // BURN, CPU, BURN! - for(volatile size_t i = 0; i < 40000000; i++); - } -} - static void debug_test() { char buffer[64]; @@ -101,6 +94,18 @@ static void dumpMB(const MultibootStructure *mbHeader) // TODO: MB_APS_TABLE } +void cpp_init() +{ + +} + +void putsuccess() +{ + int y; kgetpos(nullptr, &y); + ksetpos(CONSOLE_WIDTH - 9, y); + kputs("[success]"); +} + void init(const MultibootStructure *mbHeader) { (void)debug_test; @@ -113,37 +118,42 @@ void init(const MultibootStructure *mbHeader) //dumpMB(mbHeader); kputs("Initialize physical memory management: "); - pmm_init(mbHeader); - kputs("success.\n"); + pmm_init(mbHeader); + putsuccess(); + // uint32_t freeMem = pmm_calc_free(); //kprintf("Free memory: %d B, %d kB, %d MB\n", freeMem, freeMem >> 10, freeMem >> 20); - ksleep(1); - kputs("Initialize virtual memory management: "); - vmm_init(); - kputs("success.\n"); + vmm_init(); + putsuccess(); - kputs("Initialize interrupts: "); + kputs("Initialize interrupts:"); intr_init(); - kputs("success.\n"); + putsuccess(); - kputs("Enable hw interrupts: "); + kputs("Enable hw interrupts:"); irq_enable(); - kputs("success.\n"); + putsuccess(); - //__asm__ volatile("sti"); + kputs("Prepare heap memory:"); + for(uintptr_t ptr = 0x400000; ptr < 0x800000; ptr += 4096) + { + vmm_map(ptr, (uintptr_t)pmm_alloc(), VM_PROGRAM); + } + putsuccess(); - kputs("Prepare heap memory: "); - for(uintptr_t ptr = 0x400000; ptr < 0x800000; ptr += 4096) - { - vmm_map(ptr, (uintptr_t)pmm_alloc(), VM_PROGRAM); - } - kputs("success.\n"); + kputs("Initialize timer:"); + timer_init(); + putsuccess(); + + kputs("Initialize C++ objects: "); + cpp_init(); + putsuccess(); while(1) { kputs("x"); - ksleep(1); + sleep(1); } } diff --git a/src/interrupts.c b/src/interrupts.c index 74c922a..038a14d 100644 --- a/src/interrupts.c +++ b/src/interrupts.c @@ -10,6 +10,8 @@ static uint64_t gdt[GDT_ENTRIES]; static uint64_t idt[IDT_ENTRIES]; +static InterruptHandler handlers[IDT_ENTRIES]; + static const char *interruptNames[] = { "Divide-by-zero Error",// 0 (0x0) Fault #DE No "Debug",// 1 (0x1) Fault/Trap #DB No @@ -65,21 +67,39 @@ static const size_t interruptNameCount = sizeof(interruptNames) / sizeof(interru #include "intr_stubs.h" +void intr_set_handler(uint32_t interrupt, InterruptHandler handler) +{ + if(interrupt < IDT_ENTRIES) { + handlers[interrupt] = handler; + } +} + void intr_routine(CpuState *state) { const char *name = "Unknown"; if(state->intr < interruptNameCount) name = interruptNames[state->intr]; + InterruptHandler handler = handlers[state->intr]; if(state->intr < 0x20) { - kprintf("\n\x12\x04Exception [%d] %s!\x12\0x7\n", state->intr, name); - while(1) - { - __asm__ volatile("cli; hlt"); + if(handler != nullptr) { + handler(state); + } else { + kprintf("\n\x12\x04Exception [%d] %s!\x12\0x7\n", state->intr, name); + while(1) + { + __asm__ volatile("cli; hlt"); + } } } if (state->intr >= 0x20 && state->intr <= 0x2f) { + if(handler != nullptr) { + handler(state); + } else { + kprintf("[Unhandled IRQ: %d]", state->intr); + } + if (state->intr >= 0x28) { // EOI an Slave-PIC @@ -90,11 +110,15 @@ void intr_routine(CpuState *state) } else { - kprintf("\n\x12\x04Interrupt [%d] %s occurred!\x12\0x7\n", state->intr, name); - while(1) - { - // Prozessor anhalten - __asm__ volatile("cli; hlt"); + if(handler != nullptr) { + handler(state); + } else { + kprintf("\n\x12\x04Interrupt [%d] %s occurred!\x12\0x7\n", state->intr, name); + while(1) + { + // Prozessor anhalten + __asm__ volatile("cli; hlt"); + } } } } @@ -240,8 +264,16 @@ static void init_idt(void) __asm__ volatile("lidt %0" : : "m" (idtp)); } +void init_handlers(void) +{ + memset(handlers, 0, sizeof(handlers)); +} + void intr_init(void) { + // Initialize handler table + init_handlers(); + // Initialize global descriptor table init_gdt(); diff --git a/src/kernel.h b/src/kernel.h deleted file mode 100644 index 9f5dfdd..0000000 --- a/src/kernel.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -void die(const char *msg); - -void ksleep(uint32_t time); diff --git a/src/stdlib.c b/src/stdlib.c index b649b36..010c8f4 100644 --- a/src/stdlib.c +++ b/src/stdlib.c @@ -1,4 +1,23 @@ -#include "stdlib.h" +#include +#include + +void* realloc (void* ptr, size_t size) +{ + void *n = malloc(size); + memcpy(n, ptr, size); + free(ptr); + return n; +} + +void exit(int errorCode) +{ + static char buffer[128]; + static char tmp[10]; + strcpy(buffer, "Program exited with error code "); + strcat(buffer, itoa(errorCode, tmp, 10)); + strcat(buffer, ".\n"); + die(buffer); +} static void reverse(char *str, int length) { diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 0000000..ae4e02d --- /dev/null +++ b/src/timer.c @@ -0,0 +1,33 @@ + +#include "timer.h" +#include "interrupts.h" + +static volatile uint64_t ticks = 0; + +static void timer_irq() +{ + ticks++; +} + +void timer_init() +{ + ticks = 0; + intr_set_handler(0x20, timer_irq); +} + +uint64_t timer_get() +{ + return ticks; +} + +void timer_set(uint64_t time) +{ + ticks = time; +} + +void sleep(uint64_t t) +{ + uint64_t end = timer_get() + t; + while(timer_get() < end); +} + diff --git a/trainOS.pro b/trainOS.pro index 616f6d8..d6fbd42 100644 --- a/trainOS.pro +++ b/trainOS.pro @@ -12,23 +12,32 @@ SOURCES += \ src/stdlib.c \ src/vmm.c \ trainscript/tsvm.cpp \ - trainscript/main.cpp + trainscript/main.cpp \ + src/timer.c \ + src/cplusplus.cpp HEADERS += \ - src/console.h \ - src/cpustate.h \ - src/interrupts.h \ - src/intr_stubs.h \ - src/io.h \ - src/kernel.h \ - src/multiboot.h \ - src/pmm.h \ - src/stdlib.h \ - src/varargs.h \ - src/vmm.h \ + include/console.h \ + include/cpustate.h \ + include/interrupts.h \ + include/intr_stubs.h \ + include/io.h \ + include/kernel.h \ + include/multiboot.h \ + include/pmm.h \ + include/stdlib.h \ + include/varargs.h \ + include/vmm.h \ trainscript/common.h \ trainscript/tsvm.hpp \ - trainscript/typeid.hpp + trainscript/typeid.hpp \ + include/timer.h \ + include/ker/string.hpp \ + include/ker/pair.hpp \ + include/ker/vector.hpp \ + include/ker/dictionary.hpp \ + include/string.h \ + include/ker/new.hpp DISTFILES += \ asm/intr_common_handler.S \ diff --git a/trainscript/Makefile b/trainscript/Makefile index 9273a25..518f241 100644 --- a/trainscript/Makefile +++ b/trainscript/Makefile @@ -15,10 +15,10 @@ main.o: main.cpp tsvm.hpp common.h tsvm.o: tsvm.cpp tsvm.hpp common.h g++ $(CCFLAGS) -c tsvm.cpp -o tsvm.o -lex.yy.o: lex.yy.cpp tsvm.hpp common.h +lex.yy.o: lexyy.cpp tsvm.hpp common.h g++ $(CCFLAGS) -c lex.yy.cpp -o lex.yy.o -trainscript.tab.o: lex.yy.cpp trainscript.tab.cpp tsvm.hpp common.h +trainscript.tab.o: lex.yy.cpp trainscript_tab.cpp tsvm.hpp common.h g++ $(CCFLAGS) -c trainscript.tab.cpp -o trainscript.tab.o lex.yy.cpp: trainscript.l diff --git a/trainscript/file01.ts b/trainscript/file01.ts index 1131503..101e2e3 100644 --- a/trainscript/file01.ts +++ b/trainscript/file01.ts @@ -36,6 +36,7 @@ BEGIN 1 → iter; 0 → r; WHILE iter < max DO +# FOR iter FROM 1 TO max DO BEGIN IF (iter % 5) = 0 THEN r + iter → r; diff --git a/trainscript/trainscript.l b/trainscript/trainscript.l index 9010d6a..0c51e5d 100644 --- a/trainscript/trainscript.l +++ b/trainscript/trainscript.l @@ -1,7 +1,7 @@ %{ #include #include "common.h" -#include "trainscript.tab.h" +#include "trainscript.tab.hpp" %} %option noyywrap diff --git a/trainscript/trainscript.tab.hpp b/trainscript/trainscript.tab.hpp new file mode 100644 index 0000000..d4df285 --- /dev/null +++ b/trainscript/trainscript.tab.hpp @@ -0,0 +1,128 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + 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, either version 3 of the License, or + (at your option) any later version. + + 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, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_YY_TRAINSCRIPT_TRAINSCRIPT_TAB_HPP_INCLUDED +# define YY_YY_TRAINSCRIPT_TRAINSCRIPT_TAB_HPP_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + TAB = 258, + TYPENAME = 259, + SEMICOLON = 260, + COLON = 261, + COMMA = 262, + PIPE = 263, + PLUS = 264, + MINUS = 265, + MULTIPLY = 266, + DIVIDE = 267, + MODULO = 268, + LBRACKET = 269, + RBRACKET = 270, + RARROW = 271, + LARROW = 272, + OP_LT = 273, + OP_LE = 274, + OP_GT = 275, + OP_GE = 276, + OP_EQ = 277, + OP_NEQ = 278, + REAL = 279, + INT = 280, + IDENTIFIER = 281, + KW_PUB = 282, + KW_PRI = 283, + KW_VAR = 284, + KW_PTR = 285, + KW_VOID = 286, + KW_INT = 287, + KW_REAL = 288, + KW_TEXT = 289, + KW_BOOL = 290, + KW_BEGIN = 291, + KW_END = 292, + KW_IF = 293, + KW_THEN = 294, + KW_ELSE = 295, + KW_ELSEIF = 296, + KW_REPEAT = 297, + KW_FROM = 298, + KW_TO = 299, + KW_UNTIL = 300, + KW_WHILE = 301, + KW_DO = 302 + }; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 44 "trainscript/trainscript.y" /* yacc.c:1909 */ + + float fval; + int ival; + char *text; + int indentation; + trainscript::Type type; + VariableDeclaration varDecl; + MethodDeclaration method; + MethodBody *body; + MethodHeader methodHeader; + trainscript::Instruction *instruction; + LocalVariable *local; + ExpressionList *expressions; + +#line 117 "trainscript/trainscript.tab.hpp" /* yacc.c:1909 */ +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int yyparse (ParserData * context); + +#endif /* !YY_YY_TRAINSCRIPT_TRAINSCRIPT_TAB_HPP_INCLUDED */ diff --git a/trainscript/trainscript.y b/trainscript/trainscript.y index c7efd17..a981a82 100644 --- a/trainscript/trainscript.y +++ b/trainscript/trainscript.y @@ -400,13 +400,13 @@ typeName: void yyerror(void *scanner, const char *s) { if(scanner == nullptr) { - printf("Error: %s\n", s); + kprintf("Error: %s\n", s); return; } int line = 0; // yyget_lineno(scanner); int col = 0; //yyget_column(scanner); char *text = yyget_text(scanner); - printf( + kprintf( "[%d:%d] Error: %s at '%s'\n", line, col, s, diff --git a/trainscript/tsvm.cpp b/trainscript/tsvm.cpp index 5b1ab12..de8db1c 100644 --- a/trainscript/tsvm.cpp +++ b/trainscript/tsvm.cpp @@ -1,11 +1,13 @@ +extern "C" { #include -#include +#include +} #include "common.h" #include "tsvm.hpp" -#include "trainscript.tab.h" +#include "trainscript.tab.hpp" #include "trainscript.l.h" namespace trainscript @@ -74,39 +76,29 @@ namespace trainscript } } - Variable Method::invoke(std::vector arguments) + Variable Method::invoke(ker::Vector arguments) { LocalContext context(this->module); for(auto var : this->module->variables) { - context.insert({ var.first, var.second }); + context.add(var.first, var.second); } if(this->returnValue.second.type.usable()) { - context.insert({ this->returnValue.first, &this->returnValue.second }); + context.add(this->returnValue.first, &this->returnValue.second); } - if(arguments.size() != this->arguments.size()) { - printf("MECKER anzahl!\n"); - return Variable(); + if(arguments.length() != this->arguments.length()) { + return Variable::Invalid; } - for(size_t i = 0; i < this->arguments.size(); i++) { + for(size_t i = 0; i < this->arguments.length(); i++) { if(this->arguments[i].second.type != arguments[i].type) { - printf("MECKER argtyp!\n"); - return Variable(); + return Variable::Invalid; } - context.insert({this->arguments[i].first, new Variable(arguments[i]) }); + context.add(this->arguments[i].first, new Variable(arguments[i])); } for(auto local : this->locals) { - context.insert({ local.first, new Variable(local.second) }); - } - - if(verbose) { - printf("executing with local context:\n"); - for(auto &ref : context) - { - printf(" %s : %s\n", ref.first.c_str(), typeName(ref.second->type.id)); - } + context.add(local.first, new Variable(local.second)); } this->block->execute(context); @@ -123,7 +115,7 @@ namespace trainscript switch(lhs.type.id) { case TypeID::Int:return mkvar(lhs.integer + rhs.integer); case TypeID::Real: return mkvar(lhs.real + rhs.real); - default: printf("addition not supported for %s.\n", typeName(lhs.type.id)); break; + default: kprintf("addition not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; } } @@ -132,7 +124,7 @@ namespace trainscript switch(lhs.type.id) { case TypeID::Int: return mkvar(lhs.integer - rhs.integer); case TypeID::Real:return mkvar(lhs.real - rhs.real); - default: printf("subtraction not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; + default: kprintf("subtraction not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; } } @@ -141,7 +133,7 @@ namespace trainscript switch(lhs.type.id) { case TypeID::Int: return mkvar(lhs.integer * rhs.integer); case TypeID::Real: return mkvar(lhs.real * rhs.real); - default: printf("multiplication not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; + default: kprintf("multiplication not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; } } @@ -150,7 +142,7 @@ namespace trainscript switch(lhs.type.id) { case TypeID::Int: return mkvar(lhs.integer / rhs.integer); case TypeID::Real: return mkvar(lhs.real / rhs.real); - default: printf("division not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; + default: kprintf("division not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; } } @@ -159,7 +151,7 @@ namespace trainscript switch(lhs.type.id) { case TypeID::Int: return mkvar(lhs.integer % rhs.integer); // case TypeID::Real: mkvar(lhs.real % rhs.real); - default: printf("modulo not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; + default: kprintf("modulo not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; } } @@ -170,7 +162,7 @@ namespace trainscript case TypeID::Real: return mkbool(lhs.real == rhs.real); case TypeID::Bool: return mkbool(lhs.boolean == rhs.boolean); default: - printf("equals not supported for %s.\n", typeName(lhs.type.id)); + kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; } } @@ -182,7 +174,7 @@ namespace trainscript case TypeID::Real: return mkbool(lhs.real != rhs.real); case TypeID::Bool: return mkbool(lhs.boolean != rhs.boolean); default: - printf("inequals not supported for %s.\n", typeName(lhs.type.id)); + kprintf("inequals not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; } } @@ -194,7 +186,7 @@ namespace trainscript case TypeID::Int: return mkbool(lhs.integer < rhs.integer); case TypeID::Real: return mkbool(lhs.real < rhs.real); default: - printf("equals not supported for %s.\n", typeName(lhs.type.id)); + kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; } } @@ -205,7 +197,7 @@ namespace trainscript case TypeID::Int: return mkbool(lhs.integer <= rhs.integer); case TypeID::Real: return mkbool(lhs.real <= rhs.real); default: - printf("equals not supported for %s.\n", typeName(lhs.type.id)); + kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; } } @@ -216,7 +208,7 @@ namespace trainscript case TypeID::Int: return mkbool(lhs.integer > rhs.integer); case TypeID::Real: return mkbool(lhs.real > rhs.real); default: - printf("equals not supported for %s.\n", typeName(lhs.type.id)); + kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; } } @@ -227,7 +219,7 @@ namespace trainscript case TypeID::Int: return mkbool(lhs.integer >= rhs.integer); case TypeID::Real: return mkbool(lhs.real >= rhs.real); default: - printf("equals not supported for %s.\n", typeName(lhs.type.id)); + kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; } } diff --git a/trainscript/tsvm.hpp b/trainscript/tsvm.hpp index d1170de..be627a5 100644 --- a/trainscript/tsvm.hpp +++ b/trainscript/tsvm.hpp @@ -1,9 +1,18 @@ #pragma once -#include -#include -#include -#include +extern "C" { +#include +#include +} + +// #include + +#include +#include +#include + +// #include +// #include #include "typeid.hpp" @@ -32,7 +41,6 @@ namespace trainscript } Type dereference() const { - if(pointer == 0) throw std::exception(); return { id, pointer - 1 }; } @@ -72,10 +80,10 @@ namespace trainscript void printval() const { switch(this->type.id) { - case TypeID::Int: printf("%d", this->integer); break; - case TypeID::Real: printf("%f", this->real); break; - case TypeID::Bool: printf("%s", this->boolean ? "TRUE" : "FALSE"); break; - default: printf("???"); break; + case TypeID::Int: kprintf("%d", this->integer); break; + case TypeID::Real: kprintf("%f", this->real); break; + case TypeID::Bool: kprintf("%s", this->boolean ? "TRUE" : "FALSE"); break; + default: kprintf("???"); break; } } @@ -107,33 +115,24 @@ namespace trainscript class Module; - class LocalContext : - public std::map + class LocalContext : + public ker::Dictionary { public: Module * const module = nullptr; LocalContext(Module *mod) : - std::map(), + ker::Dictionary(), module(mod) { } - int depth; - - LocalContext() : depth(0) { } - - void indent() { - for(int i = 0; i < depth; i++) printf(" "); - } - - Variable *get(const std::string &name) + Variable *get(const ker::String &name) { - if(this->count(name) > 0) { + if(this->contains(name)) { return this->at(name); } else { - printf("Variable %s not found!\n", name.c_str()); return nullptr; } } @@ -151,7 +150,7 @@ namespace trainscript public Instruction { public: - std::vector instructions; + ker::Vector instructions; ~Block() { for(auto *instr : instructions) delete instr; @@ -171,23 +170,23 @@ namespace trainscript Module *module; Instruction *block; bool isPublic; - std::vector> arguments; - std::map locals; - std::pair returnValue; + ker::Vector> arguments; + ker::Dictionary locals; + ker::Pair returnValue; Method(Module *module, Instruction *block) : module(module), block(block) { } - Variable invoke(std::vector arguments); + Variable invoke(ker::Vector arguments); }; class Module { public: - std::map variables; - std::map methods; + ker::Dictionary variables; + ker::Dictionary methods; public: Module(); ~Module(); @@ -225,12 +224,6 @@ namespace trainscript ConstantExpression(Variable value) : value(value) { } Variable execute(LocalContext &context) const override { - if(verbose) { - context.indent(); - printf("constant: "); - this->value.printval(); - printf("\n"); - } return this->value; } }; @@ -239,15 +232,10 @@ namespace trainscript public Instruction { public: - std::string variableName; - VariableExpression(std::string variableName) : variableName(variableName) { } + ker::String variableName; + VariableExpression(ker::String variableName) : variableName(variableName) { } Variable execute(LocalContext &context) const override { - if(verbose) { - context.indent(); - printf("variable: %s\n", this->variableName.c_str()); - } - auto *var = context.get(this->variableName); if(var == nullptr) { return Variable::Invalid; @@ -261,9 +249,9 @@ namespace trainscript public Instruction { public: - std::string variableName; + ker::String variableName; Instruction *expression; - VariableAssignmentExpression(std::string variableName, Instruction *expression) : + VariableAssignmentExpression(ker::String variableName, Instruction *expression) : variableName(variableName), expression(expression) { @@ -272,19 +260,9 @@ namespace trainscript Variable execute(LocalContext &context) const override { if(this->expression == nullptr) { - if(verbose) printf("Invalid instruction in assignment.\n"); return Variable::Invalid; } - if(verbose) context.depth++; Variable result = this->expression->execute(context); - if(verbose) context.depth--; - - if(verbose) { - context.indent(); - printf("assign "); - result.printval(); - printf(" to %s\n", this->variableName.c_str()); - } Variable *target = context.get(this->variableName); if(target == nullptr) { @@ -292,10 +270,6 @@ namespace trainscript } if(target->type != result.type) { - if(verbose) printf( - "Assignment does not match: %s → %s\n", - typeName(result.type.id), - this->variableName.c_str()); return Variable::Invalid; } @@ -303,7 +277,7 @@ namespace trainscript case TypeID::Int: target->integer = result.integer; break; case TypeID::Real: target->real = result.real; break; case TypeID::Bool: target->boolean = result.boolean; break; - default: if(verbose) printf("assignment not supported.\n"); break; + default: break; } return result; @@ -314,10 +288,10 @@ namespace trainscript public Instruction { public: - std::string methodName; - std::vector parameters; + ker::String methodName; + ker::Vector parameters; - MethodInvokeExpression(std::string methodName) : + MethodInvokeExpression(ker::String methodName) : methodName(methodName) { @@ -325,18 +299,16 @@ namespace trainscript Variable execute(LocalContext &context) const override { - Method *method = context.module->method(this->methodName.c_str()); + Method *method = context.module->method(this->methodName.str()); if(method == nullptr) { - if(verbose) printf("method %s not found!\n", this->methodName.c_str()); return Variable::Invalid; } - if(verbose) context.depth++; - std::vector vars(this->parameters.size()); - for(int i = 0; i < vars.size(); i++) { + ker::Vector vars(this->parameters.length()); + vars.resize(this->parameters.length()); + for(size_t i = 0; i < vars.length(); i++) { vars[i] = this->parameters.at(i)->execute(context); } - if(verbose) context.depth--; return method->invoke(vars); } @@ -347,7 +319,7 @@ namespace trainscript public Instruction { public: - Instruction *rhs, *lhs; + Instruction *lhs, *rhs; ArithmeticExpression(Instruction *lhs, Instruction *rhs) : lhs(lhs), @@ -358,36 +330,19 @@ namespace trainscript Variable execute(LocalContext &context) const override { if(this->lhs == nullptr) { - if(verbose) printf("lhs: Invalid instruction in addition.\n"); return Variable::Invalid; } if(this->rhs == nullptr) { - if(verbose) printf("rhs: Invalid instruction in addition.\n"); return Variable::Invalid; } - if(verbose) context.depth++; Variable left = this->lhs->execute(context); Variable right = this->rhs->execute(context); - if(verbose) context.depth--; if(left.type != right.type) { - if(verbose) printf( - "Arithmetic types do not match: %s != %s\n", - typeName(left.type.id), - typeName(right.type.id)); return Variable::Invalid; } - if(verbose) { - context.indent(); - printf("Arithmetic on "); - left.printval(); - printf(" and "); - right.printval(); - printf("\n"); - } - return OP(left, right); } }; @@ -410,13 +365,11 @@ namespace trainscript Variable execute(LocalContext &context) const override { if(this->condition == nullptr) { - if(verbose) printf("IF: missing condition.\n"); return Variable::Invalid; } Variable result = this->condition->execute(context); if(result.type != Type::Boolean) { - if(verbose) printf("IF: Invalid condition type.\n"); return Variable::Invalid; } if((result.boolean == true) && (this->blockTrue != nullptr)) { @@ -443,7 +396,6 @@ namespace trainscript Variable execute(LocalContext &context) const override { if(this->block == nullptr) { - if(verbose) printf("REPEAT: missing block.\n"); return Variable::Invalid; } @@ -473,23 +425,18 @@ namespace trainscript Variable execute(LocalContext &context) const override { if(this->condition == nullptr) { - if(verbose) printf("REPEAT: missing condition.\n"); return Variable::Invalid; } if(this->block == nullptr) { - if(verbose) printf("REPEAT: missing block.\n"); return Variable::Invalid; } while(true) { Variable cond = this->condition->execute(context); - if(cond.type != Type::Boolean) { - printf("REPEAT: Invalid expression type.\n"); return Variable::Invalid; } - if(cond.boolean == false) { break; }