Trang Language

Trang là ngôn ngữ kịch bản minimalist được nhúng trong thinsh (tiny shell), kết hợp sức mạnh của shell UNIX với khả năng lập trình có cấu trúc. Trang cung cấp cú pháp tiếng Việt đơn giản để viết các script tự động hóa, xử lý logic phức tạp, và tương tác trực tiếp với hệ thống Linux.

Ngôn ngữ chạy trên một stack-based virtual machine với bytecode được biên dịch thời gian chạy, cho phép thực thi nhanh và cô lập môi trường thông qua khối trang.

Tính năng chi tiết

1. Biến & Biểu thức số nguyên

Trang hỗ trợ biến số nguyên với cú pháp gán đơn giản và các toán tử số học, logic cơ bản.

✓ Cú pháp đơn giản ✓ Không cần khai báo kiểu ✗ Chỉ hỗ trợ int

Khả năng:

  • Toán tử số học: +, -, *, /
  • Toán tử so sánh: <, >, ==
  • Biến tự động khởi tạo = 0
  • Hỗ trợ biểu thức lồng nhau với dấu ngoặc
trang
# Biến và biểu thức
x = 10
y = x * 2 + 5
result = (x + y) / 3

# So sánh
isGreater = x > 5  # 1 (true) hoặc 0 (false)
isEqual = x == 10  # 1

in x        # In: 10
in y        # In: 25
in result   # In: 11

2. Cấu trúc điều khiển

Hỗ trợ rẽ nhánh neu...thi...het và vòng lặp khi...thi...het với cú pháp tiếng Việt tự nhiên.

✓ Cú pháp rõ ràng → Không có else/elif → While only (no for)

Rẽ nhánh (neu-thi-het):

trang
x = 15

neu x > 10 thi
    in x
    in 1
het

# Nested conditions
neu x > 5 thi
    neu x < 20 thi
        in 999
    het
het

Vòng lặp (khi-thi-het):

trang
# Fibonacci(20)
n = 20
a = 0
b = 1
i = 0

khi i < n thi
    t = a + b
    a = b
    b = t
    i = i + 1
het

in a  # 6765

3. Khối sandbox (trang...het)

Tính năng độc đáo: tạo môi trường cô lập để thực thi code, trả về giá trị mà không ảnh hưởng đến state bên ngoài.

✓ Isolation hoàn toàn ✓ Return value tự động ✗ Không lồng nhau

Cơ chế hoạt động:

  • Backup toàn bộ stack và biến hiện tại
  • Reset môi trường sandbox (biến = 0, stack rỗng)
  • Thực thi code trong sandbox
  • Lấy giá trị top-of-stack làm return value
  • Restore state bên ngoài
  • Push return value lên stack ngoài
trang
x = 10
in x  # 10

# Sandbox thay đổi x bên trong
y = trang
    x = 999  # x local trong sandbox
    123      # return value
het

in y  # 123 (return value từ sandbox)
in x  # 10 (x ngoài không đổi!)

# Factorial trong sandbox
fact10 = trang
    n = 10
    acc = 1
    i = 1
    khi i < n + 1 thi
        acc = acc * i
        i = i + 1
    het
    acc  # return value
het

in fact10  # 3628800

4. Tích hợp lệnh shell

Gọi trực tiếp các lệnh Linux từ script Trang, kết hợp scripting với automation.

✓ Seamless integration → Output vào stdout

Lệnh builtin hỗ trợ:

  • date - Hiển thị thời gian hệ thống
  • pwd - Thư mục hiện tại
  • whoami - Tên user
  • ls, dir - Liệt kê files
  • ps - Danh sách processes
  • cd, exit, help, history
trang
i = 0
khi i < 5 thi
    date  # In timestamp
    pwd   # In working directory
    in i
    i = i + 1
het

whoami  # In username
ls      # List files

5. Quản lý jobs (Background/Foreground)

Shell hỗ trợ chạy processes ở background và quản lý jobs như bash.

✓ Background mode ✓ Job control

Chức năng:

  • Chạy nền: command &
  • Foreground: fg <job_id>
  • Kill, stop, resume processes
  • Xử lý SIGINT (Ctrl+C) cho child process
  • Job table tracking
bash
# Trong thinsh
thinsh> sleep 100 &
[1] Running: sleep 100

thinsh> ps
# Xem processes

thinsh> fg 1
# Đưa job 1 lên foreground

# Ctrl+C để kill process

6. Biến môi trường riêng

Quản lý biến môi trường độc lập với bash, lưu persistent trong env.txt.

✓ Persistent storage → Tách biệt bash

Commands:

  • set <key> <value> - Đặt biến
  • get <key> - Xem giá trị
  • Lưu vào env.txt dạng KEY=VALUE
bash
thinsh> set API_KEY abc123
thinsh> set PORT 8080
thinsh> get API_KEY
abc123
thinsh> get PORT
8080

Kiến trúc nội bộ

Stack Virtual Machine

Trang sử dụng stack-based VM để thực thi bytecode, tương tự JVM hoặc Python bytecode interpreter.

Cấu trúc VM (MAY_AO):

Thành phần Mô tả Kích thước
stack[1024] Stack chính cho tính toán 1024 int
vars[1024] Mảng biến toàn cục 1024 int
pc Program counter (chỉ số instruction) int
sp Stack pointer (đỉnh stack) int
backup_* Backup cho sandbox restoration 1024 int × 2

Triển khai (C source):

c
typedef struct {
  CHUONG_TRINH *program;
  int pc;
  int stack[1024];
  int sp;
  int backup_stack[1024];
  int backup_sp;
  int vars[1024];
  int backup_vars[1024];
  int is_in_trang;
} MAY_AO;

void push(MAY_AO *vm, int value) {
  if (vm->sp >= 1024) {
    printf("Loi: Tran ngan xep (Stack Overflow)!\n");
    exit(1);
  }
  vm->stack[vm->sp++] = value;
}

int pop(MAY_AO *vm) {
  if (vm->sp <= 0) {
    printf("Loi: Ngan xep rong (Stack Underflow)!\n");
    exit(1);
  }
  return vm->stack[--vm->sp];
}

Compiler (Lexer + Parser)

Compiler phân tích source code Trang thành bytecode, thực hiện lexical analysis và parsing one-pass.

Các giai đoạn:

  1. Lexer: Tokenize source thành tokens (keywords, operators, identifiers, numbers)
  2. Parser: Phân tích cú pháp và sinh bytecode
  3. Emission: Ghi opcodes vào program->code[]

Keywords được hỗ trợ:

c
typedef enum {
  TOKEN_NEU,      // if
  TOKEN_THI,      // then
  TOKEN_HET,      // end
  TOKEN_KHI,      // while
  TOKEN_TRANG,    // sandbox
  TOKEN_IN,       // print
  TOKEN_EQUAL,    // =
  TOKEN_SEMICOLON,
  TOKEN_PLUS, TOKEN_MINUS, TOKEN_STAR, TOKEN_SLASH,
  TOKEN_LESS, TOKEN_GREATER, TOKEN_EQUAL_EQUAL,
  TOKEN_LPAREN, TOKEN_RPAREN,
  TOKEN_VAR, TOKEN_NUMBER,
  TOKEN_EOF, TOKEN_ERROR, TOKEN_NEWLINE
} TU_KHOA;

static const char *keyword_names[] = {
  "neu", "thi", "het", "khi", "trang", "in"
};

Symbol table:

  • Mảng 1023 slots cho biến user
  • Slot 1023 dành riêng cho return value của trang
  • Hash table đơn giản: key → slot index

Opcodes (Instruction Set)

VM định nghĩa 17 opcodes cơ bản cho arithmetic, logic, control flow và sandbox.

Opcode Mô tả Thao tác stack
NAP Load constant lên stack push(const[operand])
LAY Load biến lên stack push(vars[operand])
CAT Store giá trị vào biến vars[operand] = pop()
CONG Cộng push(pop() + pop())
TRU Trừ b=pop(); a=pop(); push(a-b)
NHAN Nhân push(pop() * pop())
CHIA Chia (kiểm tra /0) b=pop(); a=pop(); push(a/b)
BANG So sánh == push(pop() == pop())
LON So sánh > b=pop(); a=pop(); push(a>b)
NHO So sánh < b=pop(); a=pop(); push(a<b)
NHAY Jump vô điều kiện pc = operand
NNS Jump if false (0) if (!pop()) pc = operand
IN Print giá trị / exec cmd operand=0: print; =1: exec
BO Pop và discard pop()
VAO_TRANG Enter sandbox Backup state, reset stack/vars
RA_TRANG Exit sandbox Restore state, push return value
DUNG Halt VM Exit main loop

Implementation (VM dispatch loop):

c
void run(MAY_AO *vm) {
  while (vm->pc < vm->program->code_size) {
    CHI_DAN instr = vm->program->code[vm->pc];
    vm->pc++;
    
    switch (instr.opcode) {
      case CONG: OP_CONG(vm); break;
      case TRU: OP_TRU(vm); break;
      case NHAN: OP_NHAN(vm); break;
      case CHIA: OP_CHIA(vm); break;
      case BANG: OP_BANG(vm); break;
      case LON: OP_LON(vm); break;
      case NHO: OP_NHO(vm); break;
      case NHAY: OP_NHAY(vm, instr.operand); break;
      case NNS: OP_NNS(vm, instr.operand); break;
      case CAT: OP_CAT(vm, instr.operand); break;
      case LAY: OP_LAY(vm, instr.operand); break;
      case NAP: OP_NAP(vm, instr.operand); break;
      case BO: OP_BO(vm, instr.operand); break;
      case IN: OP_IN_WITH_OPERAND(vm, instr.operand); break;
      case VAO_TRANG: OP_VAO_TRANG(vm); break;
      case RA_TRANG: OP_RA_TRANG(vm); break;
      case DUNG: return;
      default:
        printf("Loi: Opcode khong hop le!\n");
        exit(1);
    }
  }
}

Sandbox Mechanism (trang...het)

Cơ chế sandbox được triển khai thông qua 2 opcodes: VAO_TRANGRA_TRANG.

Luồng thực thi:

  1. Compile time: Emit VAO_TRANG → sandbox_code → RA_TRANG
  2. Runtime (VAO_TRANG):
    • Check nested trang (forbidden)
    • Backup sp, stack[0..sp], vars[0..1024]
    • Reset sp=0, vars[]=0
    • Set is_in_trang=1
  3. Runtime (RA_TRANG):
    • Capture result = stack[sp-1] (if sp > 0)
    • Restore sp, stack[], vars[]
    • Set is_in_trang=0
    • Push result onto restored stack
c
void OP_VAO_TRANG(MAY_AO *vm) {
  if (vm->is_in_trang) {
    printf("Loi: Khong ho tro 'trang' long nhau!\n");
    exit(1);
  }
  vm->is_in_trang = 1;

  // Backup outer state
  vm->backup_sp = vm->sp;
  for (int i = 0; i < vm->backup_sp; i++) {
    vm->backup_stack[i] = vm->stack[i];
  }
  for (int i = 0; i < 1024; i++) {
    vm->backup_vars[i] = vm->vars[i];
  }

  // Fresh sandbox state
  vm->sp = 0;
  for (int i = 0; i < 1024; i++) {
    vm->vars[i] = 0;
  }
}

void OP_RA_TRANG(MAY_AO *vm) {
  if (!vm->is_in_trang) {
    printf("Loi: 'ra_trang' khi khong o trong 'trang'!\n");
    exit(1);
  }

  // Capture return value
  int has_result = (vm->sp > 0);
  int result = has_result ? vm->stack[vm->sp - 1] : 0;

  // Restore outer state
  vm->sp = vm->backup_sp;
  for (int i = 0; i < vm->backup_sp; i++) {
    vm->stack[i] = vm->backup_stack[i];
  }
  for (int i = 0; i < 1024; i++) {
    vm->vars[i] = vm->backup_vars[i];
  }

  vm->is_in_trang = 0;

  // Push return value onto restored stack
  push(vm, result);
}

Hướng dẫn sử dụng

Build từ source

bash
# Build with readline (recommended)
make

# Build without readline
USE_READLINE=0 make

# Clean build artifacts
make clean

Chạy shell interactively

bash
./thinsh

# Shell hỗ trợ:
# - Lệnh Linux: ls, date, ps, pwd, whoami, ...
# - Builtins: cd, exit, help, history, set, get
# - Background jobs: command &
# - Job control: fg 
# - Keyboard navigation: ↑↓←→ (với readline)
# - Tab completion (với readline)

Chạy script Trang

bash
# Trong thinsh shell
thinsh> trang script.trang

# Hoặc redirect stdin
./thinsh < script.trang

Ví dụ đầy đủ

Fibonacci sequence

trang
# fib_checkpoints.trang
n = 25
i = 0
a = 0
b = 1

khi i < n thi
    t = a + b
    a = b
    b = t

    # In một vài giá trị đầu và cuối
    neu i < 5 thi
        in i
        in a
    het

    neu i > 20 thi
        in i
        in a
    het

    i = i + 1
het

in a  # F(25) = 75025

GCD (Greatest Common Divisor)

trang
a = 1071
b = 462

# Tính GCD trong sandbox
g = trang
    x = a
    y = b

    khi y > 0 thi
        q = x / y
        r = x - (q * y)
        x = y
        y = r
    het

    x  # return GCD
het

in a    # 1071
in b    # 462
in g    # 21

Collatz conjecture

trang
n0 = 27

steps = trang
    n = n0
    s = 0
    
    khi n > 1 thi
        # Kiểm tra chẵn/lẻ
        q = n / 2
        r = n - (q * 2)

        neu r == 0 thi
            n = q  # n chẵn: n = n/2
        het

        neu r > 0 thi
            n = (3 * n) + 1  # n lẻ: n = 3n+1
        het

        s = s + 1
    het
    
    s  # return số bước
het

in n0     # 27
in steps  # 111

Transaction simulation

trang
balance = 1000
amount = 275

# Kiểm tra và thực hiện giao dịch trong sandbox
newBalance = trang
    b = balance
    fee = 3
    tentative = b - amount - fee

    # Nếu không đủ tiền, trả về balance cũ
    neu tentative < 0 thi 
        b 
    het

    # Nếu đủ, trả về balance mới
    tentative
het

balance = newBalance
in balance  # 722 (1000 - 275 - 3)

Integration with shell commands

trang
i = 0
x = 10
sum = 0

khi i < 10 thi
    date  # In timestamp
    pwd   # In current directory
    in i

    # Tính score trong sandbox
    score = trang
        t = i * i
        neu t > 20 thi 
            t + x 
        het
        t + x  # Luôn return một giá trị
    het

    in score
    sum = sum + score
    i = i + 1
het

in sum

Hạn chế & Phát triển tương lai

Hạn chế hiện tại

  • Chỉ hỗ trợ kiểu dữ liệu int (không có string, float, array)
  • Không có else/elif (chỉ có neu-thi-het)
  • Không có for loop (chỉ có khi while loop)
  • Sandbox không lồng nhau được
  • Không có functions/procedures (chỉ có sandbox blocks)
  • Stack và vars giới hạn 1024 elements
  • Không có module system / import

Khả năng mở rộng

  • Kiểu dữ liệu: Thêm string, float, arrays với tagged union
  • Functions: Implement call stack và ham...het keyword
  • Control flow: Thêm khac (else), break, continue
  • I/O: File operations, network primitives
  • Optimization: Constant folding, dead code elimination
  • Debugging: Source line mapping, step debugger