Nice work! I really like this E2 computer.
I have been coding an OS recently, and I am using an assembly like language too, as it is easier to parse.
(note to mods: I just noticed my old thread is still floating around, if this is a problem, please remove the old topic and not this one)
Current version: 3.2
New features:
All that and much more (including the download), read all about it on the website.
- Cleaned up the code, but kept the bulky goodness inside.
- More freedom when using or defining values, support for memory pointers.
- Jumps and conditional jumps, improved program flow by 10000%.
- Applications can now get user input, and even bind keys. Games, anyone?
- Easier to use all around, simplified alot of functions that were needlessly complicated.
(it's on a seperate website because of the sheer amound of content needed, it'd be a headache to edit it all into a post)
While E2 code is open source and free by nature, I think it's worth mentioning that you are free to edit and redistribute your own modifications to this script. You don't even have to credit me (even tho that'd be a nice touch).
[highlight=e2]@name Bulk OS 31
@inputs Char [S Out]:wirelink Reset
@outputs Screen:string
# Generic:
@persist [Saved String Prefix FName Function File Sep]:string D:array CBlock IBlock WAIT [CMPA CMPB]:string WAITFORINPUT Scroll
# Stack:
@persist [Stack M UI BulkData]:array T:table
@trigger
@model models/cheeze/wires/cpu2.mdl
# Reset switch:
if(Reset & ~Reset & !IBlock) { reset() }
if(first() | duped()) {
# Input screen default:
Prefix = Screen = "\n\n /> "
File = "/bulkos/bulkos.txt"
Sep = ";"
Scroll = 1
# Welcome message:
DushString(":444:Welcome to BulkOS 3.2")
DushString(":444:"+"=":repeat(30))
}
if(!~Char) {
# Data update:
T["time",string] = time("hour")+":"+time("min")+":"+time("sec")
T["date",string] = time("day")+"/"+time("month")+"/"+time("year")
T["curtime",number] = curtime()
T["lastsaid",string] = lastSaid()
}
# Keyboard input:
if(changed(Char) & Char>0 & !IBlock) {
# Numpad support:
if(Char>=128 & Char<=137) {
Char = Char-128
Key = Char:toString()
}
elseif(Char == 138 ) {
Key = "/"
}
else{ Key = toChar(Char)}
# Program override:
if(UI[Char,string]!="") {
StackushString(UI[Char,string])
}
# Backspace:
elseif(Char == 127 & String:length()>=0) {
String = String:left(String:length()-1)
}
# Shift key
elseif(Char == 154) { # ignore.
}
# Print stack data (might move to program override?):
elseif(Char == 149) {
if(Stack:count()>0) {
DushString(":444: Printing stack contents:")
DushString(":444:"+"=":repeat(30))
for(I=1,Stack:count()) { DushString(":136:"+Stack[I,string]) }
DushString(":333:"+"=":repeat(30))
}
else{ DushString(":900:Action stack is empty!") }
}
# ENTER key
elseif(Char == 13) {
# Function editor:
if(FName!="") {
String = String:trim()
if(String=="exit" | String=="end") {
T[FName,string] = Function:trim()
DushString("=":repeat(30)) D
ushString(":990:Saved function '"+FName+"'.")
FName = Function = ""
}
else{
DushString(":999:"+String+Sep)
Function = Function+String+Sep
}
}
else{
Saved = String StackushString(String)
T["input",string] = String
}
# Clear string:
String = ""
# Stop waiting for input:
WAITFORINPUT = 0
}
else{ String = String + Key T["string",string] = String}
# Update screen:
Screen = Prefix+String
}
# The mighty stack processor:
if(clk("readstack")) {
A = Stack[1,string]:trim() Stack:remove(1)
PrePro = A:explode(" ")
Com = PrePro[1,string] PrePro:remove(1)
for(I=1,PrePro:count()) {
V = PrePro[I,string]
IsMemRef = V:index(1) == "#"
Clean = V:replace("#","")
IsAddr = T[Clean,string] != "" | T[Clean,number]!=0
if(IsAddr & IsMemRef) {
Str = T[Clean,string]
Num = T[Clean,number]
if(Str!="") {
PrePro[I,string] = Str
}
elseif(Num!=0) {
PrePro[I,number] = Num
}
}
elseif(IsMemRef) {
Str = M[Clean:toNumber(),string]
Num = M[Clean:toNumber(),number]
if(Str!="") {
PrePro[I,string] = Str
}
elseif(Num!=0) {
PrePro[I,number] = Num
}
}
}
All = PrePro:concat(" ")
Target = PrePro[1,string]:toNumber()
TargetS = PrePro[1,string]
# Prt:
if(Com == "prt" | Com == "print" | Com == "echo") {
DushString(All)
}
# Lock
if(Com == "lock") {
IBlock = clamp(Target,0,1)
}
# Line/Div
if(Com == "line") {
S[2038] = 1
S:writeString(" ":repeat(30),0,16,999,!Target*555+Target)
}
# Com quit:
elseif(Com == "exit" | Com == "break" | Com == "quit") {
Stack = array() DushString(":900: Ended program(s).")
}
# Wait:
elseif(Com == "wait" | Com == "hold") {
if(TargetS == "input") { WAITFORINPUT = 1 }
else{WAIT = Target}
}
# Reset:
elseif(Com == "reset" | Com == "restart") {
reset()
}
# Beep!(suck it, Fizyk!):
elseif(Com == "beep" | Com == "boop") {
soundPlay(1,0.3,"synth/tri.wav") Pitch = PrePro[1,string]:toNumber()
Pitch = (!Pitch*100)+Pitch soundPitch(1,Pitch)
}
# toByte
elseif(Com == "tobyte") {
M[Target,number] = toByte(PrePro[2,string]:left(1))
}
elseif(Com == "tochar") {
M[Target,string] = toChar(PrePro[2,string]:left(1):toNumber())
}
# Draw:
elseif(Com == "cs") {
if(TargetS == "line") {
Clamp = clamp(PrePro[3,string]:toNumber(),!PrePro[3,string]:toNumber()*999,999)
S:writeString(" ":repeat(30),0,PrePro[2,string]:toNumber(),Clamp,Clamp)
}
elseif(TargetS == "scroll" | TargetS == "scr") {
Scroll = clamp(PrePro[2,string]:toNumber(),0,1)
}
else{
Data = PrePro[2,string]:toNumber() S[Target] = Data
}
}
# Clear(console) (shortcut):
elseif(Com == "clear" | Com == "clr") {
S[2041] = 1
}
# Function editor:
elseif(Com == "func" | Com == "file" | Com == "function") {
FName = TargetS:trim()
DushString("=":repeat(30)) D
ushString(":990:Editing function '"+FName+"'")
}
# Run!:
elseif(Com == "run" | Com == "program" | Com == "call" | Com == "do") {
BulkData = All:explode(Sep)
for(I=1,BulkData:count()) { StackushString(BulkData[I,string]:trim()) }
}
# UI bind/unbind:
elseif(Com == "bind") {
PrePro:remove(1) DataS = PrePro:concat(" ")
UI[Target,string] = DataS
}
elseif(Com == "unbind") {
if(TargetS == "all") { UI = array() }
else{UI[Target,string] = ""}
}
# JUMP!
elseif(Com == "jmp" | Com == "jump") {
if(BulkData:count()>0) {
Label = TargetS+":" Stack = array()
for(I=1,BulkData:count()) {
if(BulkData[I,string]:trim() == Label:trim()) { Found = I break }
}
for(I = Found,BulkData:count()) {
StackushString(BulkData[I,string])
}
}
else{ DushString(":900:No data to jump to!") }
}
# CMP: (oh boy..)
elseif(Com == "cmp" | Com == "compare") {
CMPA = PrePro[1,string] CMPB = PrePro[2,string]
}
# Conditionals:
elseif(Com == "je" | Com == "equal") {
Cmp = CMPA == CMPB Label = TargetS
if(Cmp) { Stack = array() StackushString("jmp "+Label) }
}
elseif(Com == "jne" | Com == "notequal") {
Cmp = CMPA != CMPB Label = TargetS
if(Cmp) { Stack = array() StackushString("jmp "+Label) }
}
elseif(Com == "jle" | Com == "lessqual") {
Cmp = CMPA:toNumber() <= CMPB:toNumber() Label = TargetS
if(Cmp) { Stack = array() StackushString("jmp "+Label) }
}
elseif(Com == "jle" | Com == "less") {
Cmp = CMPA:toNumber() < CMPB:toNumber() Label = TargetS
if(Cmp) { Stack = array() StackushString("jmp "+Label) }
}
elseif(Com == "jge" | Com == "greaterequal") {
Cmp = CMPA:toNumber() >= CMPB:toNumber() Label = TargetS
if(Cmp) { Stack = array() StackushString("jmp "+Label) }
}
elseif(Com == "jg" | Com == "greater") {
Cmp = CMPA:toNumber() > CMPB:toNumber() Label = TargetS
if(Cmp) { Stack = array() StackushString("jmp "+Label) }
}
# Mov:
elseif(Com == "movnum") {
DataN = PrePro[2,string]:toNumber()
M[Target,number] = DataN
}
elseif(Com == "movstr") {
PrePro:remove(1) DataS = PrePro:concat(" ")
M[Target,string] = DataS
}
# Put/Get:
elseif(Com == "put") {
PrePro:remove(1) DataS = PrePro:concat(" ")
T[TargetS,string] = DataS
}
elseif(Com == "get") {
PrePro:remove(1)
M[Target,string] = T[PrePro:concat(" "),string]
}
# External mem:
elseif(Com == "out") {
Out[Target] = PrePro[2,string]:toNumber()
}
elseif(Com == "in") {
M[Target,number] = Out[PrePro[2,string]:toNumber()]
}
# Math:
elseif(Com == "rand") {
RandA = PrePro[2,string]:toNumber()
RandB = PrePro[3,string]:toNumber()
Random = randint(RandA,RandB)
M[Target,number] = Random
}
elseif(Com == "add") {
M[Target,number] = M[Target,number] + PrePro[2,string]:toNumber()
}
elseif(Com == "sub") {
M[Target,number] = M[Target,number] - PrePro[2,string]:toNumber()
}
elseif(Com == "div") {
M[Target,number] = M[Target,number] / PrePro[2,string]:toNumber()
}
elseif(Com == "mul") {
M[Target,number] = M[Target,number] * PrePro[2,string]:toNumber()
}
elseif(Com == "inc") {
M[Target,number] = M[Target,number] + 1
}
elseif(Com == "dec") {
M[Target,number] = M[Target,number] - 1
}
# String functions:
elseif(Com == "concat") {
PrePro:remove(1)
M[Target,string] = M[Target,string] + PrePro:concat(" ")
}
elseif(Com == "strlen") {
PrePro:remove(1)
M[Target,number] = PrePro:concat(" "):length()
}
elseif(Com == "upper") {
PrePro:remove(1)
M[Target,string] = PrePro:concat(" "):upper()
}
elseif(Com == "lower") {
PrePro:remove(1)
M[Target,string] = PrePro:concat(" "):lower()
}
elseif(Com == "trim") {
PrePro:remove(1)
M[Target,string] = PrePro:concat(" "):trim()
}
elseif(Com == "say") {
concmd("say [bulkOS]: "+All)
}
elseif(Com == "explode") {
PrePro:remove(1)
Bulk = PrePro:concat(" "):explode("")
for(I=Target,Bulk:count()) {
M[I,string] = Bulk[I,string]
}
}
# File functions:
elseif(Com == "savedb") {
SAVE = 1
}
elseif(Com == "load") {
File = "/bulkos/"+TargetS timer("reload",300)
}
elseif(Com == "write") {
WriteTo = "/bulkos/"+TargetS
PrePro:remove(1)
fileWrite(WriteTo,PrePro:concat(" "))
}
elseif(Com == "append") {
WriteTo = "/bulkos/"+TargetS
PrePro:remove(1)
fileAppend(WriteTo,PrePro:concat(" "))
}
elseif(Com == "remove") {
WriteTo = "/bulkos/"+TargetS
fileRemove(WriteTo)
}
elseif(Com == "pushmem") {
T["mem",string] = glonEncode(M)
}
elseif(Com == "pullmem") {
M = glonDecode(T["mem",string])
}
}
# File handler:
if(clk("reload") | first() | duped() | fileClk()) {
if(!fileLoaded(File)) { fileLoad(File) runOnFile(1) }
else{
if(File == "/bulkos/bulkos.txt") {
T = glonDecodeTable(fileRead(File))
StackushString("run "+T["startup",string])
}
else{
T["file",string] = fileRead(File)
T["fname",string] = File:replace("/bulkos/",""):trim()
}
}
}
if(SAVE) {
# This 'file' juggling bit is to avoid a huge file being saved into the DB inside it's slot.
Loaded = T["file",string] T["file",string] = ""
fileWrite("/bulkos/bulkos.txt",glonEncode(T))
T["file",string] = Loaded SAVE = 0
}
# Stack delay handler:
if(Stack:count()>0) {
# Delay is capped to 120 seconds by default.
Time = clamp(WAIT,5,120000) WAIT = 0
if(!WAITFORINPUT) { timer("readstack",Time) }
}
# Console print:
while(D:count()>0 & !CBlock) {
Print = D[1,string]
if(Print:index(1) == ":" & Print:index(5) == ":") {
Color = Print:sub(2,4):toNumber()
Print = Print:right(Print:length()-5):trim()
}
else{ Color = 999 }
Lines = ceil(Print:length()/30)
for(I=0,!Lines+Lines-1) {
S:writeString(Print:sub(I*31):trim(),0,17,Color,0) D:remove(1)
S[2038] = Scroll
}
}
[/highlight]
Faron: the highlighting is broken again, notice the hash in the tables?
Last edited by Filipe; 01-28-2010 at 04:37 AM.
beep boop
It's not impossible. I'm writing a banking system in bulkcode that sits on top of the OS, but sets up proxies for all the functions. The banking system is loaded on startup and completely overtakes all functions, and presents a neat ordered list with all the options:
1. View user details.
2. Create user account.
3. Delete user account.
4. Load data file.
5. Exit and restart with BulkOS. <- unloads the system from the startup, drops it in #banking, saves the db and calls a restart.
I simply input a number (1/5) and the script handles all the heavy lifting.
While it's not easy, and definetly not very functional, you CAN write another custom language on top of the existing bulkcode (yo dawg...), and just like I'm doing, the heavy lifting can be offset to a script running in the background over the main OS layer.
But honestly, the bulkOS name isn't just an attempt at sounding cute, it really fits it. At full speed, performing 5 or 6 operations per second, the E2 shoots up to 1200 ops/s, this is because all the code is parsed on run-time. For the next version I might try coming up with a simple compiler, but I have to look into it, as I don't want to give up on BulkOS's freedom when it comes to code writing (right now you can store code in strings, load it mid-code, heck, you can create a script that edits itself as you go along).
Last edited by Filipe; 01-28-2010 at 04:47 AM.
beep boop
It would be nice if it was compiled, and there was a command to invoke the compiler at runtime on a specific string.
That's what I've been thinking about, it's very possible, I'm just not sure yet how I'd accomplish it, and how I'd still keep the...wait, just figured that part out....There's still alot of things I'll have to iron out before even getting started on the actual code, but I think I might attempt to use an array, have the compiler push values and strings into the array, and then come up with a short-form code that would be created by the compiler, something like..
would translate to:Code:mov 1 this is a string yay.;
The second '1' being the string's index in the array...Off the top of my head I believe this would be much faster, since the current parser runs alot of checks on all the strings every single time, regardless of what the command is.Code:m 1 1
Thoughts? Am I in the right path with this way of thinking?
Oopsie, minor mistake, I often neglect the expression's name D:
Edit:
Made some progress on the compiler, won't go into details right now, but right now this:
Is turned into this:Code:prt Hello my name is #name
Numbers aren't transformed in any way. I think I'll attempt to compact those extra strings into a single one.Code:p $3 $4 $5 $6 #7
Edit2:
Strings now collapse correctly, this:
Becomes this:Code:prt Hello, my name is #name and I like bacon!;
Right from the start, I expect this'll cut ops by atleast half on most operations.Code:p|$1|#2|$3;
Edit3:
The first tests confirm what I mentioned previously. Operations per second increased to over 30 (couldn't get a precise reading yet), at only 300 op/s, compared to 6 operations at 1200op/s on the previous version.
Edit4:
The basics are laid down, the jmp structure now works MUCH better, I got the E2 up to 2300 op/s, at a speed AT LEAST 20x faster than before, and it was doing a pretty intensive operation.
Yay!
Edit5:
Original bulkcode:
Compiled code:Code:Main:; prt Hello; wait 1000; jmp Main;
Code:Main:p|$1w|$2j|1
Last edited by Filipe; 01-28-2010 at 05:50 PM.
beep boop
Shouldn't you like... compile into bytecode instead of strings? That'll cut down even more of your ops
This is awesome, good job.
Love the similarities to assembly.
Bookmarks