Compiler Project Language Features

Keywords

  • “let”: initiates a variable declaration.
  • “be”: acts as the assignment operator in other programming language.
  • “int”: specifies the variable is of integer type during its declaration.
  • “set”: specifies the variable is of set type during its declaration.
  • “show”: acts as the main function in other programming languages, which initialize a calculation.

Data type

Integer

  • Basic data type

  • Range between 0-4199999999

  • A single-digit integer is an arbitrary decimal number.

  • A multi-digit integer starts with a non-zero decimal number and followed by any sequence of arbitrary decimal numbers.

  • Users can only declare non-negative integers. Negative integers are constructed through subtraction operations.

Set

Arithmetic expression

Constructed data type

Users are not allowed to declare an arithmetic expression. There is no specific data type keyword for arithmetic expressions in the language. This data type only exists in the compiler. You can also check the keywords. There is no data type keyword for arithmetic expressions.

An atomic arithmetic expression is either an integer constant or an integer variable.

A compound arithmetic expression consists of two arithmetic expressions connected by an arithmetic operator (addition "+", subtraction "-", multiplication "*" ).

And parentheses are used to define substructures within expression. For example,

is parsed as:

Predicates

Constructed data type

Same as arithmetic expression, predicates are not directly declared by users but are instead managed within the compiler.

An atomic predicate is a relational comparison, which can be of two types:

  • Integer value comparison: involving the comparison of two integers using relational operator less than (“<”), greater than (“>”), or equality (“=”); or
  • Membership testing: used to determine if an element is a member of a set using the membership operator “@”.

A compound predicate is formed by combining “smaller” predicates (either atomic or compound) using logical operators:

  • Binary logical operators: two (atomic or compound) predicates connected by a conjunction (“&”) or disjunction (“|”)

  • Unary logical operators: Negation (“!”) which precedes another predicate.

For example,

and

where P, Q, and R are predicates.

Parentheses are also used to define substructures in predicates. Parentheses are essential for defining the precedence and grouping of operations within predicates, ensuring the correct evaluation of complex expressions.

Bool

Void

let be show int set+-*@<>&|!UI

def parse(self):
    self.stack.append(0)  # 初始状态
    current_token = self.tokens[self.index] if self.index < len(self.tokens) else None

    while True:
        state = self.stack[-1]  # 获取当前状态
        action, value = self.actions.get((state, current_token.token_type if current_token else "$"), (None, None))
            
        if action is None:
            print(f"Syntax Error: Unexpected token '{current_token.lexeme if current_token else 'EOF'}'")
            return
        if action == "s":  # 移入操作
            self.stack.append(value)  # 将目标状态压入栈
            self.index += 1  # 移动到下一个 token
            current_token = self.tokens[self.index] if self.index < len(self.tokens) else None
        elif action == "r":  # 规约操作
            lhs, rhs_length = self.rules[value]  # 获取产生式左部和右部长度
            print("lhs,rhs_length",lhs,rhs_length)
            for _ in range(rhs_length):  # 弹出 RHS 长度的符号
                self.stack.pop()
            state = self.stack[-1]  # 获取规约后的栈顶状态
            print(state,lhs)
            self.stack.append(self.goto[(state, lhs)])  # 根据 GOTO 表转移 
        elif action == "acc":  # 接受状态
            print("Syntactic Analysis Complete!")
            return