Extendable MiniLang

From Esolang
Jump to navigation Jump to search

Next time you create a language that is computable, write an interpreter for it!

-- ISLPTNG

Extendable MiniLang is designed by PSTF and his AI friend.

Command Set

Can you believe that? It only has 6 commands!

Basic Command Table
Command Meaning
INC x Increase x by 1.
DEC x Decrease x by 1.
JNZ x l Jump to label if x is not 0.
JMP l Jump to label if 1+1=2.
HLT Halt.
OUT x Print.

A variable is just a string made of lower alphabets.

Comments are started by a hashtag.

Variables are initially 0.

Label name is just a "variable name" with a colon after it.

Commands by other users

Examples

3 × 2

# 初始化
INC a
INC a
INC a  # a = 3 (Multiplier)
INC b
INC b  # b = 2 (Multiplicand)

# 乘法循环
outer_loop:
JNZ b transfer  # If b ≠ 0 then transfer a to temp
JMP end

transfer:
DEC b
JNZ a copy      # Assign temp with a
JMP outer_loop

copy:
DEC a
INC temp
INC a_copy
JMP copy        # Copy again

restore:
JNZ a_copy restore_a  # Restore a
JMP add_temp

restore_a:
DEC a_copy
INC a
JMP restore

add_temp:
JNZ temp add_to_c     # Add temp into c
JMP outer_loop

add_to_c:
DEC temp
INC c
JMP add_temp

end:
PRINT c  # Output 6
HALT

Interpreter

If you added a command, please update the interpreter.

import sys

class MiniLangInterpreter:
    def __init__(self, program):
        self.program = program
        self.vars = {}
        self.labels = {}
        self.instructions = []
        self.pc = 0  # Program counter
    
    def load(self):
        lines = [line.strip() for line in self.program.split('\n') 
                 if line.strip() and not line.strip().startswith('#')]
        
        # 1: collect label
        for idx, line in enumerate(lines):
            if line.endswith(':'):
                label = line[:-1]
                self.labels[label] = idx - len(self.labels)  # Label is not a command
        
        # 2: interpret the command
        for line in lines:
            if line.endswith(':'):
                continue  # Skip over the label
            parts = line.split()
            self.instructions.append(parts)
    
    def get_var(self, name):
        return self.vars.get(name, 0)
    
    def set_var(self, name, value):
        self.vars[name] = value
    
    def run(self):
        self.load()
        while 0 <= self.pc < len(self.instructions):
            cmd = self.instructions[self.pc]
            op = cmd[0].upper()
            
            try:
                if op == "INC":
                    var = cmd[1]
                    self.set_var(var, self.get_var(var) + 1)
                    self.pc += 1
                
                elif op == "DEC":
                    var = cmd[1]
                    self.set_var(var, self.get_var(var) - 1)
                    self.pc += 1
                
                elif op == "JNZ":
                    var, label = cmd[1], cmd[2]
                    if self.get_var(var) != 0:
                        self.pc = self.labels[label]
                    else:
                        self.pc += 1
                
                elif op == "JMP":  # JMP is the syntax-candy for JNZ
                    label = cmd[1]
                    self.pc = self.labels[label]
                
                elif op == "OUT":
                    var = cmd[1]
                    print(f"{var} = {self.get_var(var)}")
                    self.pc += 1
                
                elif op == "HLT":
                    break
                
                else:
                    raise RuntimeError(f"Unknown operator: {op}")
            
            except Exception as e:
                print(f"Line {self.pc+1} error: {e}")
                break

# Run from file or input
if __name__ == "__main__":
    if len(sys.argv) > 1:
        with open(sys.argv[1], 'r') as f:
            code = f.read()
    else:
        code = sys.stdin.read();
    
    interpreter = MiniLangInterpreter(code)
    interpreter.run()

Categories