Class: ToyLang::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/toy_lang/parser.rb

Overview

This it the class that parses the toy language grammatical rules are lower cased (e.g. statement) tokens are upper case (e.g. COMMA) optional rules are surrounded by parentheses

The toy language grammar is as follows

program =>
  statement*
statement =>
  function_definition |
  conditional_expression |
  function_call |
  return_statement
function_definition =>
  function_header OPEN_BLOCK expression* CLOSE_BLOCK
function_header =>
  DEF IDENTIFIER OPEN_PARENTHESES argument_list CLOSE_PARENTHESES
argument_list =>
  (IDENTIFIER ( COMMA IDENTIFIER)*)
conditional_expression =>
  IF condition OPEN_BLOCK expression* CLOSE_BLOCK
expression =>
  additive_expression
additive_expression =>
  substraction_expression PLUS substraction_expression
substraction_expression =>
  primary_expresion MINUS primary_expresion
primary_expresion =>
  NUMBER
function_call =>
  IDENTIFIER OPEN_PARENTHESES parameter_list CLOSE_PARENTHESES
parameter_list =>
  (expression ( COMMA expression)*)
return_statement =>
  RETURN expression

An example program would be def fibbo(number) {

if number == 0 { return 0 }
if number == 1 { return 1 }
return fibbo(number-1) + fibbo(number-2)

} fibbo(5)

This program should output 8

Instance Method Summary collapse

Instance Method Details

#conditional_expressionObject

conditional_expression =>

IF condition OPEN_BLOCK expression* CLOSE_BLOCK


83
84
85
# File 'lib/toy_lang/parser.rb', line 83

def conditional_expression
  return nil
end

#expressionObject

expression =>

....

!!! INCOMPLETE IMPLEMENTATION !!! To get going, expression can only be a number TODO: Do it for real



142
143
144
145
146
147
148
149
# File 'lib/toy_lang/parser.rb', line 142

def expression
  if token_is_not? :number
    nil
  end

  token = @scanner.get_next_token
  return { number: token.content }
end

#function_callObject

function_call =>

IDENTIFIER OPEN_PARENTHESES parameter_list CLOSE_PARENTHESES


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/toy_lang/parser.rb', line 89

def function_call
  unless tokens_are?(:id, :open_parentheses)
    return nil
  end

  method_name = @scanner.get_next_token.content
  @scanner.get_next_token # open parentheses
  params = parameter_list()

  # Verify close parentheses
  if token_is_not? :close_parentheses
    throw :parser_exception
  end

  @scanner.get_next_token # close parentheses

  return { function_call: method_name, params: params }
end

#function_definitionObject

function_definition =>

function_header OPEN_BLOCK expression* CLOSE_BLOCK


77
78
79
# File 'lib/toy_lang/parser.rb', line 77

def function_definition
  return nil
end

#parameter_listObject

parameter_list =>

(expression ( COMMA expression)*)


110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/toy_lang/parser.rb', line 110

def parameter_list
  expression_list = []
  expr = expression()
  return [] if expr == nil

  expression_list << expr

  while (token_is? :comma)
    @scanner.get_next_token # the comma
    expr = expression()
    expression_list << expr if expr != nil
  end

  expression_list
end

#program=(program) ⇒ Object



51
52
53
54
# File 'lib/toy_lang/parser.rb', line 51

def program=(program)
  @scanner = Scanner.new
  @scanner.set_program(program)
end

#return_statementObject

return_statement =>

RETURN expression


128
129
130
131
132
133
134
135
# File 'lib/toy_lang/parser.rb', line 128

def return_statement
  unless token_is? :return
    return nil
  end

  @scanner.get_next_token
  return {return: expression()}
end

#statementObject

statement =>

function_definition |
conditional_expression |
function_call |
return_statement


61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/toy_lang/parser.rb', line 61

def statement
  # ast => Abstract Syntax Tree
  if ((ast = function_definition) != nil)
    return ast
  elsif ((ast = conditional_expression) != nil)
    return ast
  elsif ((ast = function_call) != nil)
    return ast
  elsif ((ast = return_statement) != nil)
    return ast
  end
  throw :parser_exception
end