Skip to content

Commit

Permalink
i am batman
Browse files Browse the repository at this point in the history
  • Loading branch information
m3rashid committed Feb 9, 2024
0 parents commit d1dbdd1
Show file tree
Hide file tree
Showing 14 changed files with 317 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bin/*
!bin/.gitkeep
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build:
go build -o bin/lol main.go
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Lol Lang

Lol lang is an assembly style interpreted language with its syntax inspired from assembly
Empty file added bin/.gitkeep
Empty file.
2 changes: 2 additions & 0 deletions files/1.lol
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PRINT "hello world"
HALT
12 changes: 12 additions & 0 deletions files/2.lol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
PRINT "enter first number"
READ
PRINT "enter second number"
READ
SUB
JUMP.EQ.0 L1
PRINT "not equal"
HALT

L1:
PRINT "equal"
HALT
16 changes: 16 additions & 0 deletions files/3.lol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
PUSH 232
PUSH 1
ADD
JUMP.EQ.0 L1

LOOP:
PUSH 2
SUB
JUMP.EQ.0 L1
JUMP.GT.0 LOOP
PRINT "even"
HALT

L1:
PRINT "odd"
HALT
21 changes: 21 additions & 0 deletions files/4.lol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
PUSH 69
JUMP.EQ.0 L2
JUMP.GT.0 L0
PRINT "A"
HALT

L0:
PUSH 3
SUB
JUMP.EQ.0 L1
JUMP.GT.0 L0
PRINT "B"
HALT

L1:
PRINT "C"
HALT

L2:
PRINT "D"
HALT
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module lol

go 1.21.5
40 changes: 40 additions & 0 deletions internal/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package internal

import (
"bufio"
"errors"
"fmt"
"os"
"strings"
)

const FILE_EXTENSION = "lol"

func GetFileContents(filePath string) ([]string, error) {
if filePath == "" {
return nil, errors.New("error: Please provide file path \nUsage: lol <file-path>")
}

fileExtension := strings.Split(filePath, ".")
if fileExtension[len(fileExtension)-1] != FILE_EXTENSION {
return nil, fmt.Errorf("error: Invalid file extension. Please provide a .%s file", FILE_EXTENSION)
}

file, err := os.Open(filePath)
if err != nil {
return nil, err
}
defer file.Close()

var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, strings.Trim(scanner.Text(), " "))
}

if err := scanner.Err(); err != nil {
return nil, err
}

return lines, nil
}
73 changes: 73 additions & 0 deletions internal/interpreter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package internal

import (
"fmt"
"lol/lib"
"strconv"
)

func Interpret(tokenisedFile *Program) {
stack := lib.NewStack[int]()
programCounter := 0

for tokenisedFile.Program[programCounter] != HALT {
opcode := tokenisedFile.Program[programCounter]
programCounter++

if opcode == PUSH {
num, err := strconv.Atoi(tokenisedFile.Program[programCounter])
if err != nil {
panic(err)
}

stack.Push(num)
programCounter++

} else if opcode == POP {
stack.Pop()

} else if opcode == ADD {
a := stack.Pop()
b := stack.Pop()
stack.Push(a + b)

} else if opcode == SUB {
a := stack.Pop()
b := stack.Pop()
stack.Push(b - a)

} else if opcode == PRINT {
str := tokenisedFile.Program[programCounter]
programCounter++
fmt.Println(str)

} else if opcode == READ {
var inp int
_, err := fmt.Scan(&inp)
if err != nil {
panic(err)
}
stack.Push(inp)

} else if opcode == JUMP_EQ_0 {
if stack.Top() == 0 {
label := tokenisedFile.Program[programCounter]
programCounter = tokenisedFile.Labels[label]
} else {
programCounter++
}

} else if opcode == JUMP_GT_0 {
if stack.Top() > 0 {
label := tokenisedFile.Program[programCounter]
programCounter = tokenisedFile.Labels[label]
} else {
programCounter++
}

} else {
fmt.Println("opcode: ", opcode)
panic("Unknown opcode")
}
}
}
70 changes: 70 additions & 0 deletions internal/tokenizer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package internal

import (
"errors"
"strings"
)

const (
PUSH = "PUSH"
POP = "POP"
ADD = "ADD"
SUB = "SUB"
PRINT = "PRINT"
READ = "READ"
JUMP_EQ_0 = "JUMP.EQ.0"
JUMP_GT_0 = "JUMP.GT.0"
HALT = "HALT"
)

type Program struct {
Labels map[string]int
Program []string
}

func newProgram() Program {
return Program{
Labels: map[string]int{},
Program: []string{},
}
}

func TokenizeProgram(lines *[]string) (Program, error) {
tokenCount := 0
program := newProgram()

for _, line := range *lines {
parts := strings.Split(line, " ")
opcode := parts[0]

if opcode == "" {
continue
}

if opcode[len(opcode)-1] == ':' {
program.Labels[opcode[:len(opcode)-1]] = tokenCount
continue
}

program.Program = append(program.Program, opcode)
tokenCount++

if opcode == PUSH || opcode == JUMP_EQ_0 || opcode == JUMP_GT_0 {
program.Program = append(program.Program, parts[1])
tokenCount++
} else if opcode == PRINT {
joinStr := strings.Join(parts[1:], " ")

if joinStr[0] != '"' || joinStr[len(joinStr)-1] != '"' {
return program, errors.New("strings must be enclosed in double quotes")
}

program.Program = append(program.Program, joinStr[1:len(joinStr)-1])

tokenCount++
}

}

return program, nil
}
46 changes: 46 additions & 0 deletions lib/stack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package lib

const MAX_STACK_SIZE = 255

type Stack[T interface{}] struct {
items []T
stackPointer int
}

func NewStack[T any]() Stack[T] {
return Stack[T]{
items: []T{},
stackPointer: -1,
}
}

func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
s.stackPointer++
if len(s.items) > MAX_STACK_SIZE {
panic("stack overflow")
}
}

func (s *Stack[T]) Pop() T {
item := s.items[len(s.items)-1]
s.items = s.items[:len(s.items)-1]
s.stackPointer--
return item
}

func (s *Stack[T]) Top() T {
return s.items[len(s.items)-1]
}

func (s *Stack[T]) IsEmpty() bool {
return len(s.items) == 0
}

func (s *Stack[T]) Size() int {
return len(s.items)
}

func (s *Stack[T]) Clear() {
s.items = []T{}
}
27 changes: 27 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package main

import (
"fmt"
"lol/internal"
"os"
)

func main() {
lines, err := internal.GetFileContents(os.Args[1])
if err != nil {
fmt.Println(err)
return
}

if lines == nil {
return
}

program, err := internal.TokenizeProgram(&lines)
if err != nil {
fmt.Println(err)
return
}

internal.Interpret(&program)
}

0 comments on commit d1dbdd1

Please sign in to comment.