some stuff.

This commit is contained in:
Felix Queissner 2015-08-13 14:56:50 +02:00
parent cf02215de8
commit ddbfb0e1aa
32 changed files with 922 additions and 202 deletions

View file

@ -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))) OBJS = $(addsuffix .o,$(basename $(SRCS)))
CC = gcc CC = gcc
CXX = g++
LD = ld LD = ld
LEX=flex
YACC=bison
# define nullptr, but not NULL. # define nullptr, but not NULL.
CFLAGS = -m32 -Dnullptr=0 CFLAGS = -m32 -Dnullptr=0
ASFLAGS = 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 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 $^)) $(LD) $(LDFLAGS) -o $@ $(addprefix obj/, $(notdir $^))
%.o: %.c %.o: %.c
@ -19,6 +23,24 @@ kernel: $(OBJS)
%.o: %.S %.o: %.S
$(CC) $(CFLAGS) $(ASFLAGS) -c -o $(addprefix obj/, $(notdir $@)) $^ $(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: clean:
rm $(addprefix obj/, $(notdir $(OBJS))) rm $(addprefix obj/, $(notdir $(OBJS)))

View file

@ -1,5 +1,9 @@
#pragma once #pragma once
#if defined(__cplusplus)
extern "C" {
#endif
#define CONSOLE_WIDTH 80 #define CONSOLE_WIDTH 80
#define CONSOLE_HEIGHT 25 #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 format The format string that will be printed in formatted version.
* @param ... The format parameters that will be used to print the string. * @param ... The format parameters that will be used to print the string.
*/ */
void kprintf(const char *format, ...); void kprintf(const char *format, ...);
#if defined(__cplusplus)
}
#endif

View file

@ -1,6 +1,10 @@
#pragma once #pragma once
#include "inttypes.h" #include "inttypes.h"
#if defined(__cplusplus)
extern "C" {
#endif
typedef struct typedef struct
{ {
// Saved by interrupt routine // Saved by interrupt routine
@ -21,4 +25,8 @@ typedef struct
uint32_t eflags; uint32_t eflags;
uint32_t esp; uint32_t esp;
uint32_t ss; uint32_t ss;
} CpuState; } CpuState;
#if defined(__cplusplus)
}
#endif

View file

@ -1,4 +1,9 @@
#pragma once #pragma once
#include "cpustate.h"
#if defined(__cplusplus)
extern "C" {
#endif
#define GDTF_DATASEG 0x02 #define GDTF_DATASEG 0x02
#define GDTF_CODESEG 0x0a #define GDTF_CODESEG 0x0a
@ -16,11 +21,20 @@
#define INTR_TRAP_GATE 7 #define INTR_TRAP_GATE 7
#define INTR_TASK_GATE 5 #define INTR_TASK_GATE 5
typedef void (*InterruptHandler)(CpuState *);
/** /**
* Initializes interrupt handling and the global descriptor table. * Initializes interrupt handling and the global descriptor table.
*/ */
void intr_init(); 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. * @brief Enables physical interrupts.
*/ */
@ -37,3 +51,6 @@ static inline void irq_disable(void)
__asm__ volatile("cli"); __asm__ volatile("cli");
} }
#if defined(__cplusplus)
}
#endif

View file

@ -1,6 +1,11 @@
#pragma once #pragma once
#include "inttypes.h" #include <inttypes.h>
#if defined(__cplusplus)
extern "C" {
#endif
/** /**
* @brief Outputs a byte on the given port. * @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)); __asm__ volatile ("outb %0, %1" : : "a" (data), "Nd" (port));
} }
#if defined(__cplusplus)
}
#endif

View file

@ -0,0 +1,98 @@
#pragma once
#include "pair.hpp"
#include "vector.hpp"
namespace ker
{
template<typename Key, typename Value>
class Dictionary
{
public:
typedef Pair<Key, Value> Entry;
private:
Vector<Entry> 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();
}
};
}

16
include/ker/new.hpp Normal file
View file

@ -0,0 +1,16 @@
#pragma once
#include <inttypes.h>
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*) { }

20
include/ker/pair.hpp Normal file
View file

@ -0,0 +1,20 @@
#pragma once
namespace ker
{
template<typename First, typename Second>
struct Pair
{
First first;
Second second;
Pair() : first(), second() { }
Pair(const First &first, const Second &second) :
first(first),
second(second)
{
}
};
}

100
include/ker/string.hpp Normal file
View file

@ -0,0 +1,100 @@
#pragma once
#include <stdlib.h>
#include <inttypes.h>
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);
}
};
};

117
include/ker/vector.hpp Normal file
View file

@ -0,0 +1,117 @@
#pragma once
#include <inttypes.h>
#include "new.hpp"
namespace ker
{
template<typename T>
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<T>::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];
}
};
}

13
include/kernel.h Normal file
View file

@ -0,0 +1,13 @@
#pragma once
#include <inttypes.h>
#if defined(__cplusplus)
extern "C" {
#endif
void die(const char *msg);
#if defined(__cplusplus)
}
#endif

View file

@ -2,6 +2,10 @@
#include <inttypes.h> #include <inttypes.h>
#if defined(__cplusplus)
extern "C" {
#endif
#define MB_MEMSIZE (1<<0) #define MB_MEMSIZE (1<<0)
#define MB_BOOTDEVICE (1<<1) #define MB_BOOTDEVICE (1<<1)
#define MB_COMMANDLINE (1<<2) #define MB_COMMANDLINE (1<<2)
@ -89,3 +93,7 @@ typedef struct {
uint16_t vbeInterfaceOffset; uint16_t vbeInterfaceOffset;
uint16_t vbeInterfaceLength; uint16_t vbeInterfaceLength;
} __attribute__((packed)) MultibootStructure; } __attribute__((packed)) MultibootStructure;
#if defined(__cplusplus)
}
#endif

View file

@ -2,6 +2,10 @@
#include "multiboot.h" #include "multiboot.h"
#if defined(__cplusplus)
extern "C" {
#endif
/** /**
* Initializes physical memory management. * Initializes physical memory management.
* @param mb The multi boot structure used for gathering information about free memory. * @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. * Calculates the free memory in bytes.
*/ */
uint32_t pmm_calc_free(void); uint32_t pmm_calc_free(void);
#if defined(__cplusplus)
}
#endif

View file

@ -4,6 +4,10 @@
#include <inttypes.h> #include <inttypes.h>
#include "varargs.h" #include "varargs.h"
#if defined(__cplusplus)
extern "C" {
#endif
char *itoa(int value, char *str, int base); char *itoa(int value, char *str, int base);
int atoi(const char *str); int atoi(const char *str);
float atof(const char *str); float atof(const char *str);
@ -21,6 +25,10 @@ void *malloc(size_t size);
*/ */
void free(void *mem); 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) static inline void *memset(void *ptr, int value, size_t num)
{ {
uint8_t *it = (uint8_t*)ptr; 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); 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) static inline char *strcpy(char *destination, const char *source)
{ {
while(*source) while(*source)
@ -79,3 +101,15 @@ static inline void *calloc(size_t size)
memset(mem, 0, size); memset(mem, 0, size);
return mem; 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

3
include/string.h Normal file
View file

@ -0,0 +1,3 @@
#pragma once
#include "stdlib.h"

35
include/timer.h Normal file
View file

@ -0,0 +1,35 @@
#pragma once
#include <inttypes.h>
#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

View file

@ -1,6 +1,14 @@
#pragma once #pragma once
#if defined(__cplusplus)
extern "C" {
#endif
typedef __builtin_va_list va_list; typedef __builtin_va_list va_list;
#define va_start(ap, X) __builtin_va_start(ap, X) #define va_start(ap, X) __builtin_va_start(ap, X)
#define va_arg(ap, type) __builtin_va_arg(ap, type) #define va_arg(ap, type) __builtin_va_arg(ap, type)
#define va_end(ap) __builtin_va_end(ap) #define va_end(ap) __builtin_va_end(ap)
#if defined(__cplusplus)
}
#endif

View file

@ -2,6 +2,10 @@
#include <inttypes.h> #include <inttypes.h>
#if defined(__cplusplus)
extern "C" {
#endif
#define VM_PRESENT 0x01 #define VM_PRESENT 0x01
#define VM_WRITABLE 0x02 #define VM_WRITABLE 0x02
#define VM_USER 0x04 #define VM_USER 0x04
@ -19,3 +23,7 @@ void vmm_init(void);
* @remarks If flags is 0, the mapping will be undone. * @remarks If flags is 0, the mapping will be undone.
*/ */
void vmm_map(uintptr_t virtual, uintptr_t physical, uint32_t flags); void vmm_map(uintptr_t virtual, uintptr_t physical, uint32_t flags);
#if defined(__cplusplus)
}
#endif

24
src/cplusplus.cpp Normal file
View file

@ -0,0 +1,24 @@
#include <stdlib.h>
#include <inttypes.h>
#include <ker/new.hpp>
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 );
}

View file

@ -1,9 +1,11 @@
#include "kernel.h" #include <kernel.h>
#include "stdlib.h" #include <stdlib.h>
#include "console.h" #include <console.h>
#include "interrupts.h" #include <interrupts.h>
#include "pmm.h" #include <pmm.h>
#include "vmm.h" #include <vmm.h>
#include <timer.h>
void die(const char *msg) 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() static void debug_test()
{ {
char buffer[64]; char buffer[64];
@ -101,6 +94,18 @@ static void dumpMB(const MultibootStructure *mbHeader)
// TODO: MB_APS_TABLE // 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 init(const MultibootStructure *mbHeader)
{ {
(void)debug_test; (void)debug_test;
@ -113,37 +118,42 @@ void init(const MultibootStructure *mbHeader)
//dumpMB(mbHeader); //dumpMB(mbHeader);
kputs("Initialize physical memory management: "); kputs("Initialize physical memory management: ");
pmm_init(mbHeader); pmm_init(mbHeader);
kputs("success.\n"); putsuccess();
// uint32_t freeMem = pmm_calc_free(); // uint32_t freeMem = pmm_calc_free();
//kprintf("Free memory: %d B, %d kB, %d MB\n", freeMem, freeMem >> 10, freeMem >> 20); //kprintf("Free memory: %d B, %d kB, %d MB\n", freeMem, freeMem >> 10, freeMem >> 20);
ksleep(1);
kputs("Initialize virtual memory management: "); kputs("Initialize virtual memory management: ");
vmm_init(); vmm_init();
kputs("success.\n"); putsuccess();
kputs("Initialize interrupts: "); kputs("Initialize interrupts:");
intr_init(); intr_init();
kputs("success.\n"); putsuccess();
kputs("Enable hw interrupts: "); kputs("Enable hw interrupts:");
irq_enable(); 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: "); kputs("Initialize timer:");
for(uintptr_t ptr = 0x400000; ptr < 0x800000; ptr += 4096) timer_init();
{ putsuccess();
vmm_map(ptr, (uintptr_t)pmm_alloc(), VM_PROGRAM);
} kputs("Initialize C++ objects: ");
kputs("success.\n"); cpp_init();
putsuccess();
while(1) while(1)
{ {
kputs("x"); kputs("x");
ksleep(1); sleep(1);
} }
} }

View file

@ -10,6 +10,8 @@
static uint64_t gdt[GDT_ENTRIES]; static uint64_t gdt[GDT_ENTRIES];
static uint64_t idt[IDT_ENTRIES]; static uint64_t idt[IDT_ENTRIES];
static InterruptHandler handlers[IDT_ENTRIES];
static const char *interruptNames[] = { static const char *interruptNames[] = {
"Divide-by-zero Error",// 0 (0x0) Fault #DE No "Divide-by-zero Error",// 0 (0x0) Fault #DE No
"Debug",// 1 (0x1) Fault/Trap #DB 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" #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) void intr_routine(CpuState *state)
{ {
const char *name = "Unknown"; const char *name = "Unknown";
if(state->intr < interruptNameCount) if(state->intr < interruptNameCount)
name = interruptNames[state->intr]; name = interruptNames[state->intr];
InterruptHandler handler = handlers[state->intr];
if(state->intr < 0x20) if(state->intr < 0x20)
{ {
kprintf("\n\x12\x04Exception [%d] %s!\x12\0x7\n", state->intr, name); if(handler != nullptr) {
while(1) handler(state);
{ } else {
__asm__ volatile("cli; hlt"); 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 (state->intr >= 0x20 && state->intr <= 0x2f)
{ {
if(handler != nullptr) {
handler(state);
} else {
kprintf("[Unhandled IRQ: %d]", state->intr);
}
if (state->intr >= 0x28) if (state->intr >= 0x28)
{ {
// EOI an Slave-PIC // EOI an Slave-PIC
@ -90,11 +110,15 @@ void intr_routine(CpuState *state)
} }
else else
{ {
kprintf("\n\x12\x04Interrupt [%d] %s occurred!\x12\0x7\n", state->intr, name); if(handler != nullptr) {
while(1) handler(state);
{ } else {
// Prozessor anhalten kprintf("\n\x12\x04Interrupt [%d] %s occurred!\x12\0x7\n", state->intr, name);
__asm__ volatile("cli; hlt"); while(1)
{
// Prozessor anhalten
__asm__ volatile("cli; hlt");
}
} }
} }
} }
@ -240,8 +264,16 @@ static void init_idt(void)
__asm__ volatile("lidt %0" : : "m" (idtp)); __asm__ volatile("lidt %0" : : "m" (idtp));
} }
void init_handlers(void)
{
memset(handlers, 0, sizeof(handlers));
}
void intr_init(void) void intr_init(void)
{ {
// Initialize handler table
init_handlers();
// Initialize global descriptor table // Initialize global descriptor table
init_gdt(); init_gdt();

View file

@ -1,7 +0,0 @@
#pragma once
#include <inttypes.h>
void die(const char *msg);
void ksleep(uint32_t time);

View file

@ -1,4 +1,23 @@
#include "stdlib.h" #include <stdlib.h>
#include <kernel.h>
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) static void reverse(char *str, int length)
{ {

33
src/timer.c Normal file
View file

@ -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);
}

View file

@ -12,23 +12,32 @@ SOURCES += \
src/stdlib.c \ src/stdlib.c \
src/vmm.c \ src/vmm.c \
trainscript/tsvm.cpp \ trainscript/tsvm.cpp \
trainscript/main.cpp trainscript/main.cpp \
src/timer.c \
src/cplusplus.cpp
HEADERS += \ HEADERS += \
src/console.h \ include/console.h \
src/cpustate.h \ include/cpustate.h \
src/interrupts.h \ include/interrupts.h \
src/intr_stubs.h \ include/intr_stubs.h \
src/io.h \ include/io.h \
src/kernel.h \ include/kernel.h \
src/multiboot.h \ include/multiboot.h \
src/pmm.h \ include/pmm.h \
src/stdlib.h \ include/stdlib.h \
src/varargs.h \ include/varargs.h \
src/vmm.h \ include/vmm.h \
trainscript/common.h \ trainscript/common.h \
trainscript/tsvm.hpp \ 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 += \ DISTFILES += \
asm/intr_common_handler.S \ asm/intr_common_handler.S \

View file

@ -15,10 +15,10 @@ main.o: main.cpp tsvm.hpp common.h
tsvm.o: tsvm.cpp tsvm.hpp common.h tsvm.o: tsvm.cpp tsvm.hpp common.h
g++ $(CCFLAGS) -c tsvm.cpp -o tsvm.o 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 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 g++ $(CCFLAGS) -c trainscript.tab.cpp -o trainscript.tab.o
lex.yy.cpp: trainscript.l lex.yy.cpp: trainscript.l

View file

@ -36,6 +36,7 @@ BEGIN
1 iter; 1 iter;
0 r; 0 r;
WHILE iter < max DO WHILE iter < max DO
# FOR iter FROM 1 TO max DO
BEGIN BEGIN
IF (iter % 5) = 0 THEN IF (iter % 5) = 0 THEN
r + iter r; r + iter r;

View file

@ -1,7 +1,7 @@
%{ %{
#include <stdlib.h> #include <stdlib.h>
#include "common.h" #include "common.h"
#include "trainscript.tab.h" #include "trainscript.tab.hpp"
%} %}
%option noyywrap %option noyywrap

View file

@ -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 <http://www.gnu.org/licenses/>. */
/* 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 */

View file

@ -400,13 +400,13 @@ typeName:
void yyerror(void *scanner, const char *s) { void yyerror(void *scanner, const char *s) {
if(scanner == nullptr) { if(scanner == nullptr) {
printf("Error: %s\n", s); kprintf("Error: %s\n", s);
return; return;
} }
int line = 0; // yyget_lineno(scanner); int line = 0; // yyget_lineno(scanner);
int col = 0; //yyget_column(scanner); int col = 0; //yyget_column(scanner);
char *text = yyget_text(scanner); char *text = yyget_text(scanner);
printf( kprintf(
"[%d:%d] Error: %s at '%s'\n", "[%d:%d] Error: %s at '%s'\n",
line, col, line, col,
s, s,

View file

@ -1,11 +1,13 @@
extern "C" {
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <console.h>
}
#include "common.h" #include "common.h"
#include "tsvm.hpp" #include "tsvm.hpp"
#include "trainscript.tab.h" #include "trainscript.tab.hpp"
#include "trainscript.l.h" #include "trainscript.l.h"
namespace trainscript namespace trainscript
@ -74,39 +76,29 @@ namespace trainscript
} }
} }
Variable Method::invoke(std::vector<Variable> arguments) Variable Method::invoke(ker::Vector<Variable> arguments)
{ {
LocalContext context(this->module); LocalContext context(this->module);
for(auto var : this->module->variables) for(auto var : this->module->variables)
{ {
context.insert({ var.first, var.second }); context.add(var.first, var.second);
} }
if(this->returnValue.second.type.usable()) { 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()) { if(arguments.length() != this->arguments.length()) {
printf("MECKER anzahl!\n"); return Variable::Invalid;
return Variable();
} }
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) { if(this->arguments[i].second.type != arguments[i].type) {
printf("MECKER argtyp!\n"); return Variable::Invalid;
return Variable();
} }
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) { for(auto local : this->locals) {
context.insert({ local.first, new Variable(local.second) }); context.add(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));
}
} }
this->block->execute(context); this->block->execute(context);
@ -123,7 +115,7 @@ namespace trainscript
switch(lhs.type.id) { switch(lhs.type.id) {
case TypeID::Int:return mkvar(lhs.integer + rhs.integer); case TypeID::Int:return mkvar(lhs.integer + rhs.integer);
case TypeID::Real: return mkvar(lhs.real + rhs.real); 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) { switch(lhs.type.id) {
case TypeID::Int: return mkvar(lhs.integer - rhs.integer); case TypeID::Int: return mkvar(lhs.integer - rhs.integer);
case TypeID::Real:return mkvar(lhs.real - rhs.real); 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) { switch(lhs.type.id) {
case TypeID::Int: return mkvar(lhs.integer * rhs.integer); case TypeID::Int: return mkvar(lhs.integer * rhs.integer);
case TypeID::Real: return mkvar(lhs.real * rhs.real); 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) { switch(lhs.type.id) {
case TypeID::Int: return mkvar(lhs.integer / rhs.integer); case TypeID::Int: return mkvar(lhs.integer / rhs.integer);
case TypeID::Real: return mkvar(lhs.real / rhs.real); 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) { switch(lhs.type.id) {
case TypeID::Int: return mkvar(lhs.integer % rhs.integer); case TypeID::Int: return mkvar(lhs.integer % rhs.integer);
// case TypeID::Real: mkvar(lhs.real % rhs.real); // 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::Real: return mkbool(lhs.real == rhs.real);
case TypeID::Bool: return mkbool(lhs.boolean == rhs.boolean); case TypeID::Bool: return mkbool(lhs.boolean == rhs.boolean);
default: 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; return Variable::Invalid;
} }
} }
@ -182,7 +174,7 @@ namespace trainscript
case TypeID::Real: return mkbool(lhs.real != rhs.real); case TypeID::Real: return mkbool(lhs.real != rhs.real);
case TypeID::Bool: return mkbool(lhs.boolean != rhs.boolean); case TypeID::Bool: return mkbool(lhs.boolean != rhs.boolean);
default: 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; return Variable::Invalid;
} }
} }
@ -194,7 +186,7 @@ namespace trainscript
case TypeID::Int: return mkbool(lhs.integer < rhs.integer); case TypeID::Int: return mkbool(lhs.integer < rhs.integer);
case TypeID::Real: return mkbool(lhs.real < rhs.real); case TypeID::Real: return mkbool(lhs.real < rhs.real);
default: 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; return Variable::Invalid;
} }
} }
@ -205,7 +197,7 @@ namespace trainscript
case TypeID::Int: return mkbool(lhs.integer <= rhs.integer); case TypeID::Int: return mkbool(lhs.integer <= rhs.integer);
case TypeID::Real: return mkbool(lhs.real <= rhs.real); case TypeID::Real: return mkbool(lhs.real <= rhs.real);
default: 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; return Variable::Invalid;
} }
} }
@ -216,7 +208,7 @@ namespace trainscript
case TypeID::Int: return mkbool(lhs.integer > rhs.integer); case TypeID::Int: return mkbool(lhs.integer > rhs.integer);
case TypeID::Real: return mkbool(lhs.real > rhs.real); case TypeID::Real: return mkbool(lhs.real > rhs.real);
default: 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; return Variable::Invalid;
} }
} }
@ -227,7 +219,7 @@ namespace trainscript
case TypeID::Int: return mkbool(lhs.integer >= rhs.integer); case TypeID::Int: return mkbool(lhs.integer >= rhs.integer);
case TypeID::Real: return mkbool(lhs.real >= rhs.real); case TypeID::Real: return mkbool(lhs.real >= rhs.real);
default: 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; return Variable::Invalid;
} }
} }

View file

@ -1,9 +1,18 @@
#pragma once #pragma once
#include <map> extern "C" {
#include <string> #include <stdlib.h>
#include <vector> #include <console.h>
#include <string.h> }
// #include <map>
#include <ker/string.hpp>
#include <ker/vector.hpp>
#include <ker/dictionary.hpp>
// #include <vector>
// #include <string.h>
#include "typeid.hpp" #include "typeid.hpp"
@ -32,7 +41,6 @@ namespace trainscript
} }
Type dereference() const { Type dereference() const {
if(pointer == 0) throw std::exception();
return { id, pointer - 1 }; return { id, pointer - 1 };
} }
@ -72,10 +80,10 @@ namespace trainscript
void printval() const void printval() const
{ {
switch(this->type.id) { switch(this->type.id) {
case TypeID::Int: printf("%d", this->integer); break; case TypeID::Int: kprintf("%d", this->integer); break;
case TypeID::Real: printf("%f", this->real); break; case TypeID::Real: kprintf("%f", this->real); break;
case TypeID::Bool: printf("%s", this->boolean ? "TRUE" : "FALSE"); break; case TypeID::Bool: kprintf("%s", this->boolean ? "TRUE" : "FALSE"); break;
default: printf("???"); break; default: kprintf("???"); break;
} }
} }
@ -107,33 +115,24 @@ namespace trainscript
class Module; class Module;
class LocalContext : class LocalContext :
public std::map<std::string, Variable*> public ker::Dictionary<ker::String, Variable*>
{ {
public: public:
Module * const module = nullptr; Module * const module = nullptr;
LocalContext(Module *mod) : LocalContext(Module *mod) :
std::map<std::string, Variable*>(), ker::Dictionary<ker::String, Variable*>(),
module(mod) module(mod)
{ {
} }
int depth; Variable *get(const ker::String &name)
LocalContext() : depth(0) { }
void indent() {
for(int i = 0; i < depth; i++) printf(" ");
}
Variable *get(const std::string &name)
{ {
if(this->count(name) > 0) { if(this->contains(name)) {
return this->at(name); return this->at(name);
} else { } else {
printf("Variable %s not found!\n", name.c_str());
return nullptr; return nullptr;
} }
} }
@ -151,7 +150,7 @@ namespace trainscript
public Instruction public Instruction
{ {
public: public:
std::vector<Instruction*> instructions; ker::Vector<Instruction*> instructions;
~Block() { ~Block() {
for(auto *instr : instructions) delete instr; for(auto *instr : instructions) delete instr;
@ -171,23 +170,23 @@ namespace trainscript
Module *module; Module *module;
Instruction *block; Instruction *block;
bool isPublic; bool isPublic;
std::vector<std::pair<std::string, Variable>> arguments; ker::Vector<ker::Pair<ker::String, Variable>> arguments;
std::map<std::string, Variable> locals; ker::Dictionary<ker::String, Variable> locals;
std::pair<std::string, Variable> returnValue; ker::Pair<ker::String, Variable> returnValue;
Method(Module *module, Instruction *block) : module(module), block(block) Method(Module *module, Instruction *block) : module(module), block(block)
{ {
} }
Variable invoke(std::vector<Variable> arguments); Variable invoke(ker::Vector<Variable> arguments);
}; };
class Module class Module
{ {
public: public:
std::map<std::string, Variable*> variables; ker::Dictionary<ker::String, Variable*> variables;
std::map<std::string, Method*> methods; ker::Dictionary<ker::String, Method*> methods;
public: public:
Module(); Module();
~Module(); ~Module();
@ -225,12 +224,6 @@ namespace trainscript
ConstantExpression(Variable value) : value(value) { } ConstantExpression(Variable value) : value(value) { }
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
if(verbose) {
context.indent();
printf("constant: ");
this->value.printval();
printf("\n");
}
return this->value; return this->value;
} }
}; };
@ -239,15 +232,10 @@ namespace trainscript
public Instruction public Instruction
{ {
public: public:
std::string variableName; ker::String variableName;
VariableExpression(std::string variableName) : variableName(variableName) { } VariableExpression(ker::String variableName) : variableName(variableName) { }
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
if(verbose) {
context.indent();
printf("variable: %s\n", this->variableName.c_str());
}
auto *var = context.get(this->variableName); auto *var = context.get(this->variableName);
if(var == nullptr) { if(var == nullptr) {
return Variable::Invalid; return Variable::Invalid;
@ -261,9 +249,9 @@ namespace trainscript
public Instruction public Instruction
{ {
public: public:
std::string variableName; ker::String variableName;
Instruction *expression; Instruction *expression;
VariableAssignmentExpression(std::string variableName, Instruction *expression) : VariableAssignmentExpression(ker::String variableName, Instruction *expression) :
variableName(variableName), variableName(variableName),
expression(expression) expression(expression)
{ {
@ -272,19 +260,9 @@ namespace trainscript
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
if(this->expression == nullptr) { if(this->expression == nullptr) {
if(verbose) printf("Invalid instruction in assignment.\n");
return Variable::Invalid; return Variable::Invalid;
} }
if(verbose) context.depth++;
Variable result = this->expression->execute(context); 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); Variable *target = context.get(this->variableName);
if(target == nullptr) { if(target == nullptr) {
@ -292,10 +270,6 @@ namespace trainscript
} }
if(target->type != result.type) { 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; return Variable::Invalid;
} }
@ -303,7 +277,7 @@ namespace trainscript
case TypeID::Int: target->integer = result.integer; break; case TypeID::Int: target->integer = result.integer; break;
case TypeID::Real: target->real = result.real; break; case TypeID::Real: target->real = result.real; break;
case TypeID::Bool: target->boolean = result.boolean; break; case TypeID::Bool: target->boolean = result.boolean; break;
default: if(verbose) printf("assignment not supported.\n"); break; default: break;
} }
return result; return result;
@ -314,10 +288,10 @@ namespace trainscript
public Instruction public Instruction
{ {
public: public:
std::string methodName; ker::String methodName;
std::vector<Instruction*> parameters; ker::Vector<Instruction*> parameters;
MethodInvokeExpression(std::string methodName) : MethodInvokeExpression(ker::String methodName) :
methodName(methodName) methodName(methodName)
{ {
@ -325,18 +299,16 @@ namespace trainscript
Variable execute(LocalContext &context) const override 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(method == nullptr) {
if(verbose) printf("method %s not found!\n", this->methodName.c_str());
return Variable::Invalid; return Variable::Invalid;
} }
if(verbose) context.depth++; ker::Vector<Variable> vars(this->parameters.length());
std::vector<Variable> vars(this->parameters.size()); vars.resize(this->parameters.length());
for(int i = 0; i < vars.size(); i++) { for(size_t i = 0; i < vars.length(); i++) {
vars[i] = this->parameters.at(i)->execute(context); vars[i] = this->parameters.at(i)->execute(context);
} }
if(verbose) context.depth--;
return method->invoke(vars); return method->invoke(vars);
} }
@ -347,7 +319,7 @@ namespace trainscript
public Instruction public Instruction
{ {
public: public:
Instruction *rhs, *lhs; Instruction *lhs, *rhs;
ArithmeticExpression(Instruction *lhs, Instruction *rhs) : ArithmeticExpression(Instruction *lhs, Instruction *rhs) :
lhs(lhs), lhs(lhs),
@ -358,36 +330,19 @@ namespace trainscript
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
if(this->lhs == nullptr) { if(this->lhs == nullptr) {
if(verbose) printf("lhs: Invalid instruction in addition.\n");
return Variable::Invalid; return Variable::Invalid;
} }
if(this->rhs == nullptr) { if(this->rhs == nullptr) {
if(verbose) printf("rhs: Invalid instruction in addition.\n");
return Variable::Invalid; return Variable::Invalid;
} }
if(verbose) context.depth++;
Variable left = this->lhs->execute(context); Variable left = this->lhs->execute(context);
Variable right = this->rhs->execute(context); Variable right = this->rhs->execute(context);
if(verbose) context.depth--;
if(left.type != right.type) { 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; return Variable::Invalid;
} }
if(verbose) {
context.indent();
printf("Arithmetic on ");
left.printval();
printf(" and ");
right.printval();
printf("\n");
}
return OP(left, right); return OP(left, right);
} }
}; };
@ -410,13 +365,11 @@ namespace trainscript
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
if(this->condition == nullptr) { if(this->condition == nullptr) {
if(verbose) printf("IF: missing condition.\n");
return Variable::Invalid; return Variable::Invalid;
} }
Variable result = this->condition->execute(context); Variable result = this->condition->execute(context);
if(result.type != Type::Boolean) { if(result.type != Type::Boolean) {
if(verbose) printf("IF: Invalid condition type.\n");
return Variable::Invalid; return Variable::Invalid;
} }
if((result.boolean == true) && (this->blockTrue != nullptr)) { if((result.boolean == true) && (this->blockTrue != nullptr)) {
@ -443,7 +396,6 @@ namespace trainscript
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
if(this->block == nullptr) { if(this->block == nullptr) {
if(verbose) printf("REPEAT: missing block.\n");
return Variable::Invalid; return Variable::Invalid;
} }
@ -473,23 +425,18 @@ namespace trainscript
Variable execute(LocalContext &context) const override { Variable execute(LocalContext &context) const override {
if(this->condition == nullptr) { if(this->condition == nullptr) {
if(verbose) printf("REPEAT: missing condition.\n");
return Variable::Invalid; return Variable::Invalid;
} }
if(this->block == nullptr) { if(this->block == nullptr) {
if(verbose) printf("REPEAT: missing block.\n");
return Variable::Invalid; return Variable::Invalid;
} }
while(true) while(true)
{ {
Variable cond = this->condition->execute(context); Variable cond = this->condition->execute(context);
if(cond.type != Type::Boolean) { if(cond.type != Type::Boolean) {
printf("REPEAT: Invalid expression type.\n");
return Variable::Invalid; return Variable::Invalid;
} }
if(cond.boolean == false) { if(cond.boolean == false) {
break; break;
} }