Class: FAM::Syntax::Parser

Inherits:
Lexer show all
Includes:
AST
Defined in:
lib/fam/syntax/parser.rb

Instance Attribute Summary collapse

Attributes inherited from Lexer

#tokens

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Lexer

lex, #lexer, #to_s

Constructor Details

#initialize(token_stream) ⇒ Parser

Returns a new instance of Parser.



9
10
11
12
# File 'lib/fam/syntax/parser.rb', line 9

def initialize token_stream
  @tokens = token_stream
  @ast = SyntaxTree.new
end

Instance Attribute Details

#astObject (readonly)

Returns the value of attribute ast.



7
8
9
# File 'lib/fam/syntax/parser.rb', line 7

def ast
  @ast
end

Class Method Details

.parse(stream) ⇒ Object



14
15
16
17
18
# File 'lib/fam/syntax/parser.rb', line 14

def self.parse stream
  obj = self.new stream
  obj.parser
  obj
end

Instance Method Details

#parse_token(t) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/fam/syntax/parser.rb', line 32

def parse_token t
  case t.type
  when :LABEL
    return LabelNode.new @tokens.current
  when :OPCODE
    case t.name
    when 'HALT'
      exit_status = NumericNode.new tokenize('0000', :NUMERIC)
      exit_status = parse_token @tokens.next if @tokens.peek.type == @NUMERIC
      return HaltNode.new exit_status
    when 'GOTO'
      label = parse_token @tokens.next
      UnexpectedToken @tokens.current unless @tokens.current.type == :IDENT
      return GotoNode.new label
    when 'STORE'
      value = parse_token @tokens.next
      @tokens.next
      ExpectedToken 'TOKEN<:OPERATOR>(`:`)', @tokens.current unless @tokens.current.name == ':'
      to = parse_token @tokens.next
      ExpectedToken 'ADDRESS or IDENT', @tokens.current unless @tokens.current.type == :ADDRESS || @tokens.current.type == :IDENT
      return StoreNode.new value, to
    when 'LOAD'
      value = parse_token @tokens.next
      @tokens.next
      ExpectedToken 'TOKEN<:OPERATOR>(`:`)', @tokens.current unless @tokens.current.name == ':'
      reg = parse_token @tokens.next
      ExpectedToken 'REGISTER', @tokens.current unless @tokens.current.type == :REGISTER
      return LoadNode.new value, reg
    when 'DATA'
      name = parse_token @tokens.next
      UnexpectedValue name unless @tokens.current.type == :IDENT
      if @tokens.peek.name == ':'
        @tokens.next
        value = parse_token @tokens.next
      else
        value = NumericNode.new tokenize('0000', :NUMERIC)
      end
      return DataNode.new name, value
    when 'ADD', 'SUB', 'MUL', 'DIV', 'MOD'
      value = parse_token @tokens.next
      @tokens.next
      ExpectedToken 'TOKEN<:OPERATOR>(`:`)', @tokens.current unless @tokens.current.name == ':'
      to = parse_token @tokens.next

      return case t.name
      when 'ADD'
        AddNode.new value, to
      when 'SUB'
        SubNode.new value, to
      when 'MUL'
        MulNode.new value, to
      when 'DIV'
        DivNode.new value, to
      when 'MOD'
        ModNode.new value, to
      end
    when 'EQUAL', 'MORE', 'LESS'
      parse_condition
    when 'IN'
      reg = parse_token @tokens.next
      ExpectedToken 'TOKEN<:REGISTER>', @tokens.current unless @tokens.current.type == :REGISTER
      return InNode.new reg
    when 'OUT', 'ASCII'
      value = parse_token @tokens.next
      if t.name == 'OUT'
        return OutNode.new value
      else
        return AsciiNode.new value
      end
    else
      abort "Unknown/unparsable OPCODE: `#{t.name}` at [#{t.line}:#{t.col}]!".red.bold
    end
  when :ADDRESS
    return AddressNode.new @tokens.current
  when :NUMERIC
    return NumericNode.new @tokens.current
  when :REGISTER
    return RegisterNode.new @tokens.current
  when :IDENT
    return IdentNode.new @tokens.current
  else
    return nil
  end
end

#parserObject



20
21
22
23
24
25
26
27
28
29
30
# File 'lib/fam/syntax/parser.rb', line 20

def parser
  @tokens.tokens.each do |t|
    break if @tokens.current.nil?
    puts "Parsing: (#{@tokens.current.to_s.brown})" if $VERBOSE
    node = parse_token @tokens.current
    puts "Parsed to: (#{node.nil? ? 'NOT PARSED'.red : node.to_s.gray})" if $VERBOSE
    @ast << node unless node.nil?
    @tokens.next
    puts if $VERBOSE
  end
end