Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- require './parser.rb'
- require './lexer.rb'
- require './token.rb'
- require './ast.rb'
- TokenType.new :LPAREN, /^[(]/m
- TokenType.new :RPAREN, /^[)]/m
- TokenType.new :SEPARATOR, /^[,;]/m
- TokenType.new(:FLOAT, /^[0-9]+\.[0-9]*(e[\+\-]?[0-9]+)?/m) {|value| value.to_f}
- TokenType.new(:INTEGER, /^[1-9][0-9]*/m) {|value| value.to_i}
- TokenType.new(:STRING, /^'(?:[^'\\]|\\.)*'/m) {|value| value[1, -1]}
- TokenType.new :OPERATOR, /^(\=\=|\!\=|and|not|or|[\+\-\/\*\^\<\>\=])/m
- TokenType.new :KEYWORD, /^(if|then|else|end|do|while|def|as|return|break|continue)/m
- TokenType.new :IDENT, /^[a-zA-Z_][a-zA-Z0-9_]*/m
- class OrangeParser < Parser
- def program
- main = ProgramNode.new
- while not peek_type == :EOF
- if optional :KEYWORD, 'def'
- main.functions << function_definition
- next
- else
- main.statements << statement
- end
- end
- main
- end
- def function_definition
- print 'enter function_definition ', @token, @stack, "\n"
- defn = definition
- arguments = definition_list
- function_block = statement_block 'end'
- expect :KEYWORD, 'end'
- return FunctionDefinitionNode.new defn, arguments, function_block
- print 'exit function_definition ', @token, @stack, "\n"
- end
- def definition_list
- expect_type :LPAREN
- if optional_type :RPAREN
- return []
- end
- definitions = [definition]
- while optional_type :SEPARATOR
- definitions << definition
- end
- expect_type :RPAREN
- return definitions
- end
- def definition
- ident = expect_type :IDENT
- expect :KEYWORD, 'as'
- type = expect_type :IDENT
- DefinitionNode.new ident.value, type.value
- end
- def statement_block *end_token
- if end_token.length == 0
- end_token = ['end']
- end
- block = StatementBlockNode.new
- while not end_token.include? @token.value
- block << statement
- end
- block
- end
- def statement
- print 'enter statement ', @token, @stack, "\n"
- if optional :KEYWORD, 'if'
- return if_statement
- elsif optional :KEYWORD, 'while'
- return while_statement
- elsif optional :KEYWORD, 'return'
- return ReturnStatementNode.new expression
- elsif optional :KEYWORD, 'contine'
- return ContinueStatementNode.new
- elsif optional :KEYWORD, 'break'
- return BreakStatementNode.new
- # because Orange has an ambiguous grammar, we need to use lookaheads here to determine
- # whether we want to use the definition production or go on and parse as an expression
- elsif peek_type == :IDENT and lookahead(0).value == 'as'
- return definition
- else
- return expression
- end
- end
- def if_statement
- print 'enter if_statement ', @token, @stack, "\n"
- condition = expression
- expect :KEYWORD, 'then'
- true_block = statement_block 'end', 'else'
- if optional :KEYWORD, 'else'
- false_block = statement_block
- else
- false_block = nil
- end
- expect :KEYWORD, 'end'
- print 'exit if_statement ', @token, @stack, "\n"
- IfStatementNode.new condition, true_block, false_block
- end
- def while_statement
- print 'enter while_statement ', @token, @stack, "\n"
- condition = expression
- expect :KEYWORD, 'do'
- loop_block = statement_block 'end'
- expect :KEYWORD, 'end'
- print 'exit while_statement ', @token, @stack, "\n"
- WhileStatementNode.new condition, loop_block
- end
- def expression
- # expression := logicand ('=' logicand)*
- print 'enter expression ', @token, @stack, "\n"
- logicand
- while optional :OPERATOR, '='
- logicand
- other = @stack.pop
- @stack << AssignmentOpNode.new(@stack.pop, other)
- end
- print 'exit expression ', @token, @stack, "\n"
- stack.pop
- end
- def logicand
- # logicand := comparand (('and'|'or') comparand)*
- print 'enter logicand ', @token, @stack, "\n"
- comparand
- while operator = value_in('and', 'or')
- comparand
- other = @stack.pop
- @stack << (operator == 'and' ? AndOpNode.new(@stack.pop, other) : OrOpNode.new(@stack.pop, other))
- end
- print 'exit logicand ', @token, @stack, "\n"
- end
- def comparand
- # comparand := summand (('<'| '>' | '==' | '!=') summand)*
- print 'enter comparand ', @token, @stack, "\n"
- summand
- while operator = value_in('<', '>', '==', '!=')
- summand
- other = @stack.pop
- case operator
- when '<'
- @stack << LessThanOpNode.new(@stack.pop, other)
- when '>'
- @stack << GreaterThanOpNode.new(@stack.pop, other)
- when '=='
- @stack << EqualToOpNode.new(@stack.pop, other)
- when '!='
- @stack << NotEqualToOpNode.new(@stack.pop, other)
- end
- end
- print 'exit comparand ', @token, @stack, "\n"
- end
- def summand
- print 'enter summand ', @token, @stack, "\n"
- # summand := factor ('+'|'-' factor)*
- term
- while operator = value_in('+', '-')
- term
- other = @stack.pop
- @stack << (operator == '+' ? AddOpNode.new(@stack.pop, other) : SubOpNode.new(@stack.pop, other))
- end
- print 'exit summand ', @token, @stack, "\n"
- end
- def term
- # term := exponent ('*'|'/' exponent)*
- print 'enter term ', @token, @stack, "\n"
- factor
- while operator = value_in('*', '/')
- factor
- other = @stack.pop
- @stack << (operator == '*' ? MulOpNode.new(@stack.pop, other) : DivOpNode.new(@stack.pop, other))
- end
- print 'exit term ', @token, @stack, "\n"
- end
- def factor
- # factor := prefix_operator ('^' prefix_operator)*
- print 'enter factor ', @token, @stack, "\n"
- exponent
- while optional :OPERATOR, '^'
- exponent
- other = @stack.pop
- @stack << ExpOpNode.new(@stack.pop, other)
- end
- print 'exit factor ', @token, @stack, "\n"
- end
- def exponent
- print 'enter exponent ', @token, @stack, "\n"
- # exponent := ('-'|'not')? atom
- if optional(:OPERATOR, '-')
- atom
- @stack << NegativeOpNode.new(@stack.pop)
- elsif optional(:OPERATOR, 'not')
- atom
- @stack << NotOpNode.new(@stack.pop)
- else
- atom
- end
- print 'exit exponent ', @token, @stack, "\n"
- end
- def atom
- print 'enter atom ', @token, @stack, "\n"
- # atom := integer | float | string | ident ('(' parameter_list ')')? | '(' expression ')'
- if value = optional_type(:INTEGER)
- @stack << IntegerNode.new(value)
- elsif value = optional_type(:FLOAT)
- @stack << FloatNode.new(value)
- elsif value = optional_type(:STRING)
- @stack << StringNode.new(value)
- elsif value = optional_type(:IDENT)
- @stack << IdentNode.new(value)
- if optional_type :LPAREN
- function_call
- end
- elsif optional_type(:LPAREN)
- expression
- expect :RPAREN, ')'
- elsif @token.value == ')'
- return
- else
- raise "Expected INTEGER, FLOAT, STRING or LPAREN, got #{@token}"
- end
- print 'exit atom ', @token, @stack, "\n"
- end
- def function_call
- print 'enter function_call ', @token, @stack, "\n"
- ident = @stack.pop
- arguments = parameter_list
- @stack << FunctionCallNode.new(ident, arguments)
- print 'exit function_call ', @token, @stack, "\n"
- end
- def parameter_list
- if optional :RPAREN, ')'
- return []
- end
- arguments = [expression]
- while optional_type :SEPARATOR
- arguments << expression
- end
- expect_type :RPAREN
- arguments
- end
- end
- #puts lexer.tokens, "\n"
- code = %Q{
- def fib as int(n as int)
- if n < 2 then
- return 1
- else
- return fib(n - 1) + fib(n - 2)
- end
- end
- }
- puts code
- lexer = LexicalAnalyser.new code
- puts lexer.tokenise
- #parser = OrangeParser.new code
- #puts parser.program
Add Comment
Please, Sign In to add comment