def unary_operator(tokens, precedences): if tokens.current.value not in ('-', '!', '?', '#'): raise ParserException('未知或未实现操作符 {0}'.format(tokens.current.value), tokens.current.line_no) token = tokens.consume('OPERATOR') right = expression(tokens, precedences.get(token.value, 0)) if right is not None: return ast.UnaryOperator(token.line_no, token.value, right) raise ParserException('操作符 {0} 右侧表达式缺失'.format(token.value), token.line_no)
def binary_operator(tokens, left, precedences): if tokens.current.value not in ('+', '-', '*', '/', '^', '%', '>', '>=', '<', '<=', '==', '!=', 'and', 'or'): raise ParserException('未知或未实现操作符 {0}'.format(tokens.current.value), tokens.current.line_no) token = tokens.consume('OPERATOR') right = expression(tokens, precedences.get(token.value, 0)) if right is not None: return ast.BinaryOperator(token.line_no, token.value, left, right) raise ParserException('操作符 {0} 右侧表达式缺失'.format(token.value), token.line_no)
def swap_statement(tokens, left): '''交换语句''' line_no = tokens.current.line_no tokens.consume('SWAP') right = expression(tokens) if isinstance(left, ast.Readonly) or isinstance(right, ast.Readonly): raise ParserException('不可将值赋予只读的关键词', tokens.current.line_no) tokens.consume('SEMICOLON') if right is not None: return ast.Swap(line_no, left, right) raise ParserException('交换语句右侧表达式缺失', token.line_no)
def assignment_statement(tokens, left): '''赋值语句''' line_no = tokens.current.line_no if isinstance(left, ast.Readonly): raise ParserException('不可将值赋予只读的关键词', tokens.current.line_no) tokens.consume('ASSIGN') right = expression(tokens) tokens.consume('SEMICOLON') if right is not None: return ast.Assignment(line_no, left, right) raise ParserException('赋值语句右侧表达式缺失', token.line_no)
def call_block_statement(tokens): token = tokens.consume('CALL') right = expression(tokens) tokens.consume('SEMICOLON') if right is not None: return ast.CallBlock(token.line_no, right) raise ParserException('操作符 {0} 右侧表达式缺失'.format(token.value), token.line_no)
def call(tokens, left, precedences): token = tokens.consume('CALL') right = expression(tokens, precedences.get(token.value, 0)) if right is None: raise ParserException('右侧调用函数 {0} 缺失'.format(token.value), token.line_no) return ast.Call(token.line_no, left, right)
def reload(tokens, left, precedences): token = tokens.consume('RELOAD') right = expression(tokens, precedences.get(token.value, 0)) if right is None: raise ParserException('重装符 {0} 右侧表达式缺失'.format(token.value), token.line_no) return ast.Reload(token.line_no, left, right)
def unfold_statement(tokens): '''展开语句''' token = tokens.consume('UNFOLD') right = expression(tokens) tokens.consume('SEMICOLON') if right is not None: return ast.Unfold(token.line_no, right) raise ParserException('操作符 {0} 右侧表达式缺失'.format(token.value), token.line_no)
def return_statement(tokens): '''返回语句''' if ParserScope.get_node_with('fun'): token = tokens.consume('RETURN') right = expression(tokens) if right is None: right = ast.Nothing(tokens.current.line_no) tokens.consume('SEMICOLON') return ast.Return(tokens.current.line_no, right) else: raise ParserException('在函数外使用return', tokens.current.line_no)
def subscript(tokens, left, precedences): token = tokens.consume('LBRACK') if tokens.current.name == 'ALWAYS': token = tokens.consume('ALWAYS') right = ast.Always(token.line_no) else: # 优先级永远低于括号内的 right = expression(tokens) tokens.consume('RBRACK') if right is None: raise ParserException('下标不能为空', token.line_no) return ast.Subscript(token.line_no, left, right)
def table(tokens, precedences): start_token = tokens.consume('LBRACK') items = [] while not tokens.is_end(): if tokens.current.name == 'ALWAYS': token = tokens.consume('ALWAYS') tokens.consume('COLON') item = expression(tokens) if item is None: raise ParserException( '映射右侧值表达式缺失'.format(tokens.current.value), tokens.current.line_no) items.append(ast.AlwaysItem(token.line_no, item)) elif tokens.current.name == 'UNFOLD': tokens.consume('UNFOLD') right = expression(tokens) if right is not None: items.append(ast.Unfold(right.line_no, right)) else: raise ParserException( '展开操作符 {0} 右侧表达式缺失'.format(tokens.current.value), tokens.current.line_no) else: left = expression(tokens) if left is None: break if tokens.current.name == 'COLON': token = tokens.consume('COLON') right = expression(tokens) if right is None: raise ParserException('映射右侧值表达式缺失', left.line_no) items.append(ast.DictItem(token.line_no, left, right)) else: items.append(ast.ListItem(left.line_no, left)) if tokens.current.name == 'COMMA': tokens.consume('COMMA') else: break tokens.consume('RBRACK') return ast.TableStatementNode(start_token.line_no, items)
def statements(tokens, scope): stmts = [] while not tokens.is_end(): parser, container = statement.get( tokens.current.name, [expression_statement, ('fun', 'program')]) if scope not in container: raise ParserException( '{} 不能在 {} 中使用'.format(tokens.current.name, scope), tokens.current.line_no) stmt = parser(tokens) if stmt: stmts.append(stmt) else: break return stmts
def reduce(tokens, left, precedences): token = tokens.consume('REDUCE') right = expression(tokens, precedences.get(token.value, 0)) if right is not None: return ast.Reduce(token.line_no, left, right) raise ParserException('操作符 {0} 右侧表达式缺失'.format(token.value), token.line_no)
def index(tokens, _): if ParserScope.get_node_with('loop'): token = tokens.consume('INDEX') return ast.Index(token.line_no) else: raise ParserException('在循环外使用index', tokens.current.line_no)
def variable(tokens, precedences): token = tokens.consume('AT') right = expression(tokens, precedences.get(token.value, 0)) if right is not None: return ast.Variable(token.line_no, right) raise ParserException('{0} 右侧表达式缺失'.format(token.value), token.line_no)
def incorrect_always(tokens, _): raise ParserException('always只能用于Table声明或下标', tokens.current.line_no)