diff --git a/Makefile b/Makefile index a43b393..12adafb 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ obj/console.o: src/console.c include/console.h include/stdlib.h \ # src/init.c obj/init.o: src/init.c include/kernel.h include/stdlib.h include/varargs.h \ include/console.h include/interrupts.h include/cpustate.h include/pmm.h \ - include/multiboot.h include/vmm.h include/timer.h + include/multiboot.h include/vmm.h include/config.h include/timer.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/init.c # src/interrupts.c @@ -69,8 +69,9 @@ obj/timer.o: src/timer.c include/timer.h include/kernel.h \ $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/timer.c # src/vmm.c -obj/vmm.o: src/vmm.c include/vmm.h include/pmm.h include/multiboot.h \ - include/stdlib.h include/varargs.h include/console.h include/kernel.h +obj/vmm.o: src/vmm.c include/config.h include/vmm.h include/pmm.h \ + include/multiboot.h include/stdlib.h include/varargs.h include/console.h \ + include/kernel.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/vmm.c # trainscript/tsvm.cpp diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..9ce3eef --- /dev/null +++ b/include/config.h @@ -0,0 +1,5 @@ +#pragma once + +/* +#define USE_VIRTUAL_MEMORY_MANAGEMENT +//*/ diff --git a/include/ker/string.hpp b/include/ker/string.hpp index 989b6c8..d097e09 100644 --- a/include/ker/string.hpp +++ b/include/ker/string.hpp @@ -46,12 +46,6 @@ namespace ker this->copyFrom(bytes, length); } - String & operator = (const String &other) - { - this->copyFrom(other.mText, other.mLength); - return *this; - } - ~String() { if(this->mText != nullptr) { @@ -82,11 +76,6 @@ namespace ker return cat; } - static String concat(const String &lhs, const String &rhs) - { - return lhs.append(rhs); - } - const uint8_t *text() const { static const uint8_t empty[] = { 0 }; @@ -122,6 +111,12 @@ namespace ker return this->mText[index]; } + String & operator = (const String &other) + { + this->copyFrom(other.mText, other.mLength); + return *this; + } + bool operator ==(const String &other) const { return this->equals(other); @@ -131,6 +126,12 @@ namespace ker { return !this->equals(other); } + + String operator +(const String &other) const + { + return this->append(other); + } + private: void copyFrom(const uint8_t *bytes, size_t length) { @@ -142,6 +143,18 @@ namespace ker this->mLength = length; this->mText[this->mLength] = 0; // last byte is always 0 } + public: + static String concat(const String &lhs, const String &rhs) + { + return lhs.append(rhs); + } + + static String fromNumber(int32_t number, int radix = 10) + { + static char buffer[64]; + itoa(number, buffer, radix); + return String(buffer); + } }; diff --git a/include/kernel.h b/include/kernel.h index 200da0d..b378a0a 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -8,6 +8,8 @@ extern "C" { void die(const char *msg); +void die_extra(const char *msg, const char *extra); + #if defined(__cplusplus) } #endif diff --git a/include/stdlib.h b/include/stdlib.h index 3cb54c7..f3327a9 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -95,6 +95,28 @@ static inline size_t strlen(const char *str) return size; } +static inline int strcmp(const char *p1, const char *p2) +{ + while(*p1) { + if(*p2 == 0) { + return 1; + } + + if(*p2 > *p1) { + return -1; + } + if(*p1 > *p2) { + return 1; + } + p1++; + p2++; + } + if (*p2) { + return -1; + } + return 0; +} + static inline void *calloc(size_t size) { void *mem = malloc(size); diff --git a/include/vmm.h b/include/vmm.h index de4299d..1988d3e 100644 --- a/include/vmm.h +++ b/include/vmm.h @@ -1,11 +1,14 @@ #pragma once #include +#include #if defined(__cplusplus) extern "C" { #endif +#if defined(USE_VIRTUAL_MEMORY_MANAGEMENT) + #define VM_PRESENT 0x01 #define VM_WRITABLE 0x02 #define VM_USER 0x04 @@ -24,6 +27,8 @@ void vmm_init(void); */ void vmm_map(uintptr_t virtual, uintptr_t physical, uint32_t flags); +#endif + #if defined(__cplusplus) } #endif diff --git a/scripts/main.ts b/scripts/main.ts index 3a1447b..eca5b04 100644 --- a/scripts/main.ts +++ b/scripts/main.ts @@ -3,11 +3,10 @@ VAR global : INT; PUB main() | i : INT BEGIN 0 -> i; - # Print numbers from 1 to 5 - WHILE ((i + 1) -> i) <= 5 DO + WHILE ((i + 1) -> i) <= 50 DO BEGIN printInt(i); - sleep(20); + sleep(2); END END diff --git a/src/init.c b/src/init.c index e0f096b..fa112dc 100644 --- a/src/init.c +++ b/src/init.c @@ -4,18 +4,28 @@ #include #include #include - #include +#include void die(const char *msg) { - kputs("\n"); - ksetcolor(COLOR_RED, COLOR_WHITE); - kputs(msg); - while(1) - { - __asm__ volatile ("cli; hlt;"); - } + die_extra(msg, ""); +} + +void die_extra(const char *msg, const char *extra) +{ + kputs("\n"); + ksetcolor(COLOR_RED, COLOR_WHITE); + kputs(msg); + if((extra != nullptr) && (strlen(extra) > 0)) { + kputs(": '"); + kputs(extra); + kputc('\''); + } + while(1) + { + __asm__ volatile ("cli; hlt;"); + } } extern size_t mallocCount; @@ -156,12 +166,14 @@ void init(const MultibootStructure *mbHeader) 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); + uint32_t freeMem = pmm_calc_free(); + kprintf("Free memory: %d B, %d kB, %d MB\n", freeMem, freeMem >> 10, freeMem >> 20); - kputs("Initialize virtual memory management: "); +#if defined(USE_VIRTUAL_MEMORY_MANAGEMENT) + kputs("Initialize virtual memory management: "); vmm_init(); putsuccess(); +#endif kputs("Initialize interrupts:"); intr_init(); @@ -171,12 +183,14 @@ void init(const MultibootStructure *mbHeader) irq_enable(); putsuccess(); +#if defined(USE_VIRTUAL_MEMORY_MANAGEMENT) kputs("Prepare heap memory:"); - for(uintptr_t ptr = 0x400000; ptr < 0x800000; ptr += 4096) + for(uintptr_t ptr = 0x400000; ptr < 0x800000; ptr += 4096) { vmm_map(ptr, (uintptr_t)pmm_alloc(), VM_PROGRAM); } putsuccess(); +#endif kputs("Initialize timer:"); timer_init(); @@ -188,8 +202,6 @@ void init(const MultibootStructure *mbHeader) timer_add_callback(1, update_statusbar); - debug_test(); - vm_start(); kputs("\x12\x04trainOS stopped.\x12\x07!\n"); diff --git a/src/malloc.c b/src/malloc.c index b835d9f..4c40570 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -173,7 +173,10 @@ void *malloc(size_t len) void free(void *p) { - freeCount++; + freeCount++; + + return; + struct __freelist *fp1, *fp2, *fpnew; char *cp1, *cp2, *cpnew; diff --git a/src/vm.cpp b/src/vm.cpp index 547a187..27f448b 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -66,7 +66,7 @@ Variable NativeMethod::invoke(Vector arguments) case TypeID::Bool: stackSize += sizeof(Int); break; case TypeID::Int: stackSize += sizeof(Int); break; case TypeID::Real: stackSize += sizeof(Real); break; - default: die("invalid argument type."); break; + default: die_extra("NativeMethod.InvalidArgument", arguments[i].type.name()); break; } } @@ -85,7 +85,6 @@ Variable NativeMethod::invoke(Vector arguments) *reinterpret_cast(stack) = arguments[i].real; stack += sizeof(Real); break; - default: die("invalid argument type."); break; } } diff --git a/src/vmm.c b/src/vmm.c index 443a3c7..a923f0b 100644 --- a/src/vmm.c +++ b/src/vmm.c @@ -1,8 +1,11 @@ -#include "vmm.h" -#include "pmm.h" -#include "stdlib.h" -#include "console.h" -#include "kernel.h" +#include +#include +#include +#include +#include +#include + +#if defined(USE_VIRTUAL_MEMORY_MANAGEMENT) typedef struct { @@ -79,3 +82,5 @@ void vmm_init(void) cr0 |= (1 << 31); __asm__ volatile("mov %0, %%cr0" : : "r" (cr0)); } + +#endif diff --git a/trainOS.pro b/trainOS.pro index 7ca7d63..031b6e3 100644 --- a/trainOS.pro +++ b/trainOS.pro @@ -39,7 +39,8 @@ HEADERS += \ include/ker/dictionary.hpp \ include/string.h \ include/ker/new.hpp \ - include/dynamic.h + include/dynamic.h \ + include/config.h DISTFILES += \ asm/intr_common_handler.S \ diff --git a/trainscript/common.h b/trainscript/common.h index c4476ef..d8c5f25 100644 --- a/trainscript/common.h +++ b/trainscript/common.h @@ -21,14 +21,29 @@ void yyerror(void *scanner, const char *s); } \ } -typedef struct +struct ParserData { char *buffer; size_t index; size_t length; trainscript::Module *module; void *scanner; -} ParserData; + char* strings[256]; + + char *strdup(const char *str) + { + for(size_t i = 0; i < 256; i++) { + if(this->strings[i] == nullptr) { + return this->strings[i] = ::strdup(str); + } + else if(strcmp(this->strings[i], str) == 0) { + return this->strings[i]; + } + } + die_extra("ParserData::strdup", "out of strings"); + } + +}; struct VariableDeclaration { diff --git a/trainscript/trainscript.l b/trainscript/trainscript.l index 00527a0..7ea6c57 100644 --- a/trainscript/trainscript.l +++ b/trainscript/trainscript.l @@ -58,7 +58,7 @@ WHILE { return KW_WHILE; } DO { return KW_DO; } [0-9]+\.[0-9]* { yylval->fval = atof(yytext); return REAL; } [0-9]+ { yylval->ival = atoi(yytext); return INT; } -[a-zA-Z0-9'_]+ { yylval->text = strdup(yytext); return IDENTIFIER; } +[a-zA-Z0-9'_]+ { yylval->text = yyextra->strdup(yytext); return IDENTIFIER; } . { yyerror(NULL, "illegal token"); } %% /* diff --git a/trainscript/tsvm.cpp b/trainscript/tsvm.cpp index 320ab1e..6fef3a8 100644 --- a/trainscript/tsvm.cpp +++ b/trainscript/tsvm.cpp @@ -58,6 +58,12 @@ namespace trainscript yylex_destroy(data.scanner); free(internalStorage); + for(size_t i = 0; i < 256; i++) { + if(data.strings[i] != nullptr) { + free(data.strings[i]); + } + } + if(valid) { return module; } else { @@ -104,11 +110,11 @@ namespace trainscript context.add(this->mReturnValue.first, &returnVariable); } if(arguments.length() != this->mArguments.length()) { - return Variable::Invalid; + die_extra("ScriptMethod::invoke", "Invalid argument count."); } for(size_t i = 0; i < this->mArguments.length(); i++) { if(this->mArguments[i].second != arguments[i].type) { - return Variable::Invalid; + die_extra("ScriptMethod::invoke", "Invalid argument type."); } context.add(this->mArguments[i].first, new Variable(arguments[i])); } @@ -176,7 +182,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: kprintf("addition not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; + default: kprintf("addition not supported for %s.\n", lhs.type.name()); return Variable::Invalid; } } @@ -185,7 +191,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: kprintf("subtraction not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; + default: kprintf("subtraction not supported for %s.\n", lhs.type.name()); return Variable::Invalid; } } @@ -194,7 +200,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: kprintf("multiplication not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; + default: kprintf("multiplication not supported for %s.\n", lhs.type.name()); return Variable::Invalid; } } @@ -203,7 +209,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: kprintf("division not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; + default: kprintf("division not supported for %s.\n", lhs.type.name()); return Variable::Invalid; } } @@ -212,7 +218,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: kprintf("modulo not supported for %s.\n", typeName(lhs.type.id)); return Variable::Invalid; + default: kprintf("modulo not supported for %s.\n", lhs.type.name()); return Variable::Invalid; } } @@ -223,7 +229,7 @@ namespace trainscript case TypeID::Real: return mkbool(lhs.real == rhs.real); case TypeID::Bool: return mkbool(lhs.boolean == rhs.boolean); default: - kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); + kprintf("equals not supported for %s.\n", lhs.type.name()); return Variable::Invalid; } } @@ -235,7 +241,7 @@ namespace trainscript case TypeID::Real: return mkbool(lhs.real != rhs.real); case TypeID::Bool: return mkbool(lhs.boolean != rhs.boolean); default: - kprintf("inequals not supported for %s.\n", typeName(lhs.type.id)); + kprintf("inequals not supported for %s.\n", lhs.type.name()); return Variable::Invalid; } } @@ -247,7 +253,7 @@ namespace trainscript case TypeID::Int: return mkbool(lhs.integer < rhs.integer); case TypeID::Real: return mkbool(lhs.real < rhs.real); default: - kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); + kprintf("equals not supported for %s.\n", lhs.type.name()); return Variable::Invalid; } } @@ -258,7 +264,7 @@ namespace trainscript case TypeID::Int: return mkbool(lhs.integer <= rhs.integer); case TypeID::Real: return mkbool(lhs.real <= rhs.real); default: - kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); + kprintf("equals not supported for %s.\n", lhs.type.name()); return Variable::Invalid; } } @@ -269,7 +275,7 @@ namespace trainscript case TypeID::Int: return mkbool(lhs.integer > rhs.integer); case TypeID::Real: return mkbool(lhs.real > rhs.real); default: - kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); + kprintf("equals not supported for %s.\n", lhs.type.name()); return Variable::Invalid; } } @@ -280,7 +286,7 @@ namespace trainscript case TypeID::Int: return mkbool(lhs.integer >= rhs.integer); case TypeID::Real: return mkbool(lhs.real >= rhs.real); default: - kprintf("equals not supported for %s.\n", typeName(lhs.type.id)); + kprintf("equals not supported for %s.\n", lhs.type.name()); return Variable::Invalid; } } diff --git a/trainscript/tsvm.hpp b/trainscript/tsvm.hpp index 9557d12..f92d9b3 100644 --- a/trainscript/tsvm.hpp +++ b/trainscript/tsvm.hpp @@ -54,6 +54,18 @@ namespace trainscript (this->pointer != other.pointer); } + const char *name() const { + switch(id) { + case TypeID::Invalid: return "INVALID"; + case TypeID::Void: return "VOID"; + case TypeID::Int: return "INT"; + case TypeID::Real: return "REAL"; + case TypeID::Text: return "TEXT"; + case TypeID::Bool: return "BOOL"; + default: return "unknown"; + } + } + static const Type Invalid; static const Type Void; static const Type Int; @@ -288,7 +300,7 @@ namespace trainscript Variable execute(LocalContext &context) const override { auto *var = context.get(this->variableName); if(var == nullptr) { - return Variable::Invalid; + die_extra("VariableExpression.VariableNotFound", this->variableName.str()); } return *var; } @@ -328,17 +340,17 @@ namespace trainscript Variable execute(LocalContext &context) const override { if(this->expression == nullptr) { - return Variable::Invalid; + die("VariableAssignmentExpression.ExpressionMissing"); } Variable result = this->expression->execute(context); Variable *target = context.get(this->variableName); if(target == nullptr) { - return Variable::Invalid; + die_extra("VariableAssignmentExpression.VariableNotFound", this->variableName.str()); } if(target->type != result.type) { - return Variable::Invalid; + die_extra("VariableAssignmentExpression.ExpectedType", result.type.name()); } switch(target->type.id) { @@ -406,7 +418,7 @@ namespace trainscript { Method *method = context.module->method(this->methodName.str()); if(method == nullptr) { - return Variable::Invalid; + die_extra("MethodInvokeExpression.MethodNotFound", this->methodName.str()); } ker::Vector vars(this->parameters.length()); @@ -467,20 +479,25 @@ namespace trainscript Variable execute(LocalContext &context) const override { if(this->lhs == nullptr) { - return Variable::Invalid; + die_extra("ArithmeticExpression.ExpressionMissing", "Left-hand side"); } if(this->rhs == nullptr) { - return Variable::Invalid; + die_extra("ArithmeticExpression.ExpressionMissing", "Right-hand side"); } Variable left = this->lhs->execute(context); Variable right = this->rhs->execute(context); if(left.type != right.type) { - return Variable::Invalid; + die("ArithmeticExpression.TypeMismatch"); } - return OP(left, right); + Variable result = OP(left, right); + + if(result.type.usable() == false) { + die_extra("ArithmeticExpression.InvalidResult", result.type.name()); + } + return result; } bool validate(LocalContext &context, ker::String &errorCode) const override { @@ -543,12 +560,12 @@ namespace trainscript Variable execute(LocalContext &context) const override { if(this->condition == nullptr) { - return Variable::Invalid; + die("IfExpression.ConditionMissing"); } Variable result = this->condition->execute(context); if(result.type != Type::Boolean) { - return Variable::Invalid; + die_extra("IfExpression.TypeMismatch", result.type.name()); } if((result.boolean == true) && (this->blockTrue != nullptr)) { this->blockTrue->execute(context); @@ -574,7 +591,7 @@ namespace trainscript Variable execute(LocalContext &context) const override { if(this->block == nullptr) { - return Variable::Invalid; + die("RepeatEndlessExpression.BlockMissing"); } while(true) @@ -603,10 +620,10 @@ namespace trainscript Variable execute(LocalContext &context) const override { if(this->condition == nullptr) { - return Variable::Invalid; + die("RepeatWhileExpression.ConditionMissing"); } if(this->block == nullptr) { - return Variable::Invalid; + die("RepeatWhileExpression.BlockMissing"); } while(true) diff --git a/trainscript/typeid.hpp b/trainscript/typeid.hpp index 57f48c2..7f9d090 100644 --- a/trainscript/typeid.hpp +++ b/trainscript/typeid.hpp @@ -11,16 +11,4 @@ namespace trainscript Text = 4, Bool = 5, }; - - static const char *typeName(TypeID id) { - switch(id) { - case TypeID::Invalid: return "INVALID"; - case TypeID::Void: return "VOID"; - case TypeID::Int: return "INT"; - case TypeID::Real: return "REAL"; - case TypeID::Text: return "TEXT"; - case TypeID::Bool: return "BOOL"; - default: return "unknown"; - } - } }