Minimialized Programming Language

From Esolang
Jump to navigation Jump to search

Minimialized Programming Language is designed by PSTF.

It is really minimialized, and I will design the One-character version of it.

Definition

Commands

program     = { statement }
statement   = if_stmt | while_stmt | let_stmt | call_stmt | return_stmt | io_stmt
if_stmt     = "if" expr "then" { statement } [ "else" { statement } ] "end"
while_stmt  = "while" expr "do" { statement } "end"
let_stmt    = "let" ID "=" expr
call_stmt   = "call" ID "(" [ expr { "," expr } ] ")"
return_stmt = "return" expr
io_stmt     = ("print" expr) | ("read" ID) | ("printch" expr) | ("readch" ID)
expr        = term { ("+" | "-" | "==" | "<" | "!=") term }
term        = factor { ("*" | "/") factor }
factor      = INT | CHAR | STRING | ID | "(" expr ")" | ("-" factor) 
            | ID "[" expr "]" | "[" [ expr { "," expr } ] "]"
CHAR        = "'" (any character) "'"
STRING      = '"' (any characters) '"'

Data types

We use integers, booleans, character, and list.

0 represents false, while other values represent true.

Identifier

Any continuous string consisting of lowercase letters, uppercase letters, Arabic numerals, and underscores is a valid identifier, except for the following:

  1. It has the same name as an existing keyword. Solution: Add 'my' in front or slightly modify the format.
  2. Starts with a number. Solution: Add an underscore before the number.

Functions

Functions uniformly use global variables instead of parameters. To be more precise, a function is actually a subroutine.

List Processing

  • append(list, value) will append something to the list.
  • length(list) will return the size of the list.
  • chr(value) will return the corresponding character with the encoding point of value.
  • ord(value) will return the corresponding encoding point of the character value.

Example Programs

Hello, World!

let string = "Hello, World!"
let i = 0
while i < length(string) do
    printch string[i]
end

Fibonacci

read n
call fib
print result
return 0

function fib
  if n < 2 then
    let result = n
    return 0
  else
    let n1 = n - 1
    let n2 = n - 2
    let n = n1
    call fib
    let temp = result
    let n = n2
    call fib
    let result = temp + result
    return 0
  end
end

Intepreter

Python

import sys

class MinilangInterpreter:
    def __init__(self):
        self.vars = {}
        self.functions = {}
        self.output = []
    
    def parse(self, code):
        lines = [line.strip() for line in code.split('\n') if line.strip()]
        functions = {}
        main_code = []
        
        i = 0
        while i < len(lines):
            if lines[i] == 'function':
                func_name = lines[i+1]
                i += 2
                func_body = []
                while i < len(lines) and lines[i] != 'end':
                    func_body.append(lines[i])
                    i += 1
                functions[func_name] = func_body
            else:
                main_code.append(lines[i])
            i += 1
        
        return main_code, functions
    
    def eval_expr(self, expr):
        expr = expr.strip()
        
        # Handle string literals
        if expr.startswith('"') and expr.endswith('"'):
            return list(expr[1:-1])
            
        # Handle character literals
        if expr.startswith("'") and expr.endswith("'") and len(expr) == 3:
            return expr[1]
        
        # Handle list literals
        if expr.startswith('[') and expr.endswith(']'):
            if expr == '[]':
                return []
            elements = expr[1:-1].split(',')
            return [self.eval_expr(elem.strip()) for elem in elements]
        
        # Handle list indexing: var[expr]
        if '[' in expr and expr.endswith(']'):
            var_name, index_expr = expr.split('[', 1)
            index_expr = index_expr[:-1]  # Remove trailing ]
            var_name = var_name.strip()
            index = self.eval_expr(index_expr)
            
            if var_name in self.vars and isinstance(self.vars[var_name], list):
                if isinstance(index, int) and 0 <= index < len(self.vars[var_name]):
                    return self.vars[var_name][index]
            return 0
        
        # Handle built-in functions
        if expr.startswith('length(') and expr.endswith(')'):
            list_expr = expr[7:-1]
            lst = self.eval_expr(list_expr)
            return len(lst) if isinstance(lst, list) else 0
            
        if expr.startswith('chr(') and expr.endswith(')'):
            num_expr = expr[4:-1]
            num = self.eval_expr(num_expr)
            return chr(num) if isinstance(num, int) else ' '
            
        if expr.startswith('ord(') and expr.endswith(')'):
            char_expr = expr[4:-1]
            char = self.eval_expr(char_expr)
            return ord(char) if isinstance(char, str) and len(char) == 1 else 0
        
        # Integer literals
        if expr.isdigit() or (expr[0] == '-' and expr[1:].isdigit()):
            return int(expr)
        
        # Variables
        if expr in self.vars:
            return self.vars[expr]
        
        # Comparisons
        if '==' in expr:
            left, right = expr.split('==', 1)
            return 1 if self.eval_expr(left) == self.eval_expr(right) else 0
            
        if '!=' in expr:
            left, right = expr.split('!=', 1)
            return 1 if self.eval_expr(left) != self.eval_expr(right) else 0
        
        if '<' in expr:
            left, right = expr.split('<', 1)
            return 1 if self.eval_expr(left) < self.eval_expr(right) else 0
        
        # Arithmetic
        if '+' in expr:
            left, right = expr.split('+', 1)
            left_val = self.eval_expr(left)
            right_val = self.eval_expr(right)
            # Handle string concatenation or arithmetic addition
            if isinstance(left_val, str) and isinstance(right_val, str):
                return left_val + right_val
            elif isinstance(left_val, int) and isinstance(right_val, int):
                return left_val + right_val
            else:
                return 0
        
        if '-' in expr and expr.count('-') == 1 and not expr.startswith('-'):
            left, right = expr.split('-', 1)
            return self.eval_expr(left) - self.eval_expr(right)
        
        if '*' in expr:
            left, right = expr.split('*', 1)
            return self.eval_expr(left) * self.eval_expr(right)
        
        if '/' in expr:
            left, right = expr.split('/', 1)
            right_val = self.eval_expr(right)
            return self.eval_expr(left) // right_val if right_val != 0 else 0
        
        # Unary minus
        if expr.startswith('-'):
            return -self.eval_expr(expr[1:])
        
        # Parentheses
        if expr.startswith('(') and expr.endswith(')'):
            return self.eval_expr(expr[1:-1])
        
        return 0
    
    def execute(self, code, is_function=False):
        i = 0
        while i < len(code):
            line = code[i]
            
            if line.startswith('let '):
                # Handle let x = expr and let x[index] = expr
                rest = line[4:].strip()
                if '[' in rest and ']=' in rest:
                    # List assignment: let var[index] = expr
                    var_name, rest = rest.split('[', 1)
                    index_expr, expr = rest.split(']=', 1)
                    var_name = var_name.strip()
                    index = self.eval_expr(index_expr)
                    value = self.eval_expr(expr.strip())
                    
                    if var_name in self.vars and isinstance(self.vars[var_name], list):
                        if isinstance(index, int) and 0 <= index < len(self.vars[var_name]):
                            self.vars[var_name][index] = value
                else:
                    # Regular assignment
                    parts = rest.split('=', 1)
                    var = parts[0].strip()
                    expr = parts[1].strip()
                    self.vars[var] = self.eval_expr(expr)
                
            elif line.startswith('if '):
                # if expr then ... [else ...] end
                cond = line[3:].split('then', 1)[0].strip()
                if self.eval_expr(cond):
                    j = i + 1
                    block = []
                    while j < len(code) and code[j] != 'else' and code[j] != 'end':
                        block.append(code[j])
                        j += 1
                    self.execute(block, is_function)
                    while j < len(code) and code[j] != 'end':
                        j += 1
                    i = j
                else:
                    j = i + 1
                    while j < len(code) and code[j] != 'else':
                        j += 1
                    if j < len(code) and code[j] == 'else':
                        j += 1
                        block = []
                        while j < len(code) and code[j] != 'end':
                            block.append(code[j])
                            j += 1
                        self.execute(block, is_function)
                    i = j
                    
            elif line.startswith('while '):
                # while expr do ... end
                cond = line[6:].split('do', 1)[0].strip()
                j = i + 1
                block = []
                while j < len(code) and code[j] != 'end':
                    block.append(code[j])
                    j += 1
                
                while self.eval_expr(cond):
                    self.execute(block.copy(), is_function)
                i = j
                
            elif line.startswith('call '):
                # call function or built-in
                rest = line[5:].strip()
                if rest.startswith('append(') and rest.endswith(')'):
                    # Built-in append function
                    args = rest[7:-1].split(',', 1)
                    if len(args) == 2:
                        list_expr = args[0].strip()
                        value_expr = args[1].strip()
                        lst = self.eval_expr(list_expr)
                        value = self.eval_expr(value_expr)
                        if isinstance(lst, list):
                            lst.append(value)
                else:
                    # User-defined function
                    func_name = rest.split('(')[0].strip()
                    if func_name in self.functions:
                        self.execute(self.functions[func_name].copy(), True)
                    
            elif line.startswith('return '):
                expr = line[7:].strip()
                return self.eval_expr(expr)
                
            elif line.startswith('print '):
                expr = line[6:].strip()
                value = self.eval_expr(expr)
                if isinstance(value, list):
                    # Print list as string
                    self.output.append(''.join(str(c) for c in value))
                else:
                    self.output.append(str(value))
                    
            elif line.startswith('printch '):
                expr = line[8:].strip()
                value = self.eval_expr(expr)
                if isinstance(value, str) and len(value) == 1:
                    self.output.append(value)
                elif isinstance(value, int):
                    self.output.append(chr(value))
                else:
                    self.output.append('?')
                    
            elif line.startswith('read '):
                var = line[5:].strip()
                try:
                    value = int(input())
                    self.vars[var] = value
                except:
                    self.vars[var] = 0
                    
            elif line.startswith('readch '):
                var = line[7:].strip()
                try:
                    char = input()[0]  # Get first character
                    self.vars[var] = char
                except:
                    self.vars[var] = ' '
                    
            i += 1
        
        return 0
    
    def run(self, code):
        main_code, self.functions = self.parse(code)
        self.execute(main_code)
        return ''.join(self.output)

# Example usage and tests
if __name__ == "__main__":
    interpreter = MinilangInterpreter()
    
    # Test string reversal
    reverse_code = """
    let text = "hello"
    let reversed = []
    let i = length(text) - 1

    while i >= 0 do
      call append(reversed, text[i])
      let i = i - 1
    end

    let i = 0
    while i < length(reversed) do
      printch reversed[i]
      let i = i + 1
    end
    """
    
    print("String reversal test:")
    print(interpreter.run(reverse_code))
    print()
    
    # Test list operations
    list_code = """
    let numbers = [1, 2, 3, 4, 5]
    let sum = 0
    let i = 0

    while i < length(numbers) do
      let sum = sum + numbers[i]
      let i = i + 1
    end

    print "Sum: "
    print sum
    """
    
    print("List sum test:")
    interpreter2 = MinilangInterpreter()
    print(interpreter2.run(list_code))

Categories