Class: XfOOrth::Parser

Inherits:
Object show all
Defined in:
lib/fOOrth/compiler/parser.rb,
lib/fOOrth/compiler/parser/skip.rb,
lib/fOOrth/compiler/parser/normal.rb,
lib/fOOrth/compiler/parser/special.rb,
lib/fOOrth/compiler/parser/get_string.rb

Overview

  • compiler/parser/get_string.rb - Extract string literals from code source.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source) ⇒ Parser

Initialize this parser.
Parameters

  • source - The source of the text to be parsed.



20
21
22
# File 'lib/fOOrth/compiler/parser.rb', line 20

def initialize(source)
  @source = source
end

Instance Attribute Details

#sourceObject (readonly)

The source of the text to be parsed.



15
16
17
# File 'lib/fOOrth/compiler/parser.rb', line 15

def source
  @source
end

Instance Method Details

#get_stringObject

Get the balance of a string from the source code source.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/fOOrth/compiler/parser/get_string.rb', line 10

def get_string
  vm = Thread.current[:vm]
  vm.quotes, done, result = 1, false, ''

  begin
    next_char = @source.get

    if next_char == "\\"
      break if process_backslash(result)
    elsif next_char == '"' || @source.eoln?
      vm.quotes, done = 0, true
    elsif next_char >= ' '
      result << next_char
    end
  end until done

  result
end

#get_wordObject

Get the next forth word from the source code source. This method recognizes and skips over comments in the source code.
Returns:

  • A string with the next non-comment language element or nil if none

could be found.


14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/fOOrth/compiler/parser/normal.rb', line 14

def get_word
  loop do
    return nil unless (word = get_word_raw)

    if word == '('
      skip_over_comment
    elsif word == '//'
      skip_to_eoln
    else
      return word
    end
  end
end

#get_word_or_stringObject

Get the next forth word and any embedded string data. This is used to support the quoted compiler mode.
Returns:

  • A string with the next non-comment language element or nil if none

could be found.


Endemic Code Smells

  • :reek:TooManyStatements



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/fOOrth/compiler/parser/special.rb', line 16

def get_word_or_string
  return nil unless (word = get_word)

  if word[-1] == '"'
    vm = Thread.current[:vm]
    vm.quotes, skip, done = 1, false, false

    until done
      return nil unless (next_char = @source.get)
      word << next_char

      if skip
        skip = false
      elsif next_char == '"'
        vm.quotes, done = 0, true
      else
        skip = (next_char == '\\')
      end
    end
  end

  word
end

#get_word_rawObject

Get the next forth word from the source code source. Recognizes, but does not process comments in the source code.
Returns:

  • A string with the next language element or nil if none could be found.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/fOOrth/compiler/parser/normal.rb', line 32

def get_word_raw
  #Skip white space.
  return nil unless (next_char = skip_white_space)

  #Gather the word token.
  word = ''

  begin
    word << next_char

    #Check for the three special cases.
    break if ['(', '//'].include?(word) || (next_char == '"')

    next_char = @source.get
  end while next_char && next_char > ' '

  word
end

#process_16_bitObject

Process a 16 bit hex character constant.



59
60
61
62
63
# File 'lib/fOOrth/compiler/parser/get_string.rb', line 59

def process_16_bit
  hex = process_hex_character + process_hex_character +
        process_hex_character + process_hex_character
  eval("\"\\u#{hex}\"")
end

#process_8_bitObject

Process an 8 bit hex character constant.



53
54
55
56
# File 'lib/fOOrth/compiler/parser/get_string.rb', line 53

def process_8_bit
  hex = process_hex_character + process_hex_character
  eval("\"\\x#{hex}\"")
end

#process_backslash(buffer) ⇒ Object

Process a backlash character found with a string in the source text.
Endemic Code Smells

  • :reek:TooManyStatements



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/fOOrth/compiler/parser/get_string.rb', line 32

def process_backslash(buffer)
  next_char = @source.get

  if next_char == ' ' && @source.eoln?
    next_char = skip_white_space_or_to_eoln
    return true if ['"', ' '].include?(next_char)
  elsif next_char == 'n'
    next_char = "\n"
  elsif next_char == 'x'
    next_char = process_8_bit
  elsif next_char == 'u'
    next_char = process_16_bit
  elsif next_char != "\\" && next_char != '"'
    error "F10: Invalid string literal value: '\\#{next_char}'"
  end

  buffer << next_char
  false
end

#process_hex_characterObject

Get a hex character from the input stream.



66
67
68
69
70
71
# File 'lib/fOOrth/compiler/parser/get_string.rb', line 66

def process_hex_character
  next_char = @source.get
  error "F10: Invalid hex character: '#{next_char}'" unless /\h/ =~ next_char

  next_char
end

#skip_over_commentObject

Skip over a portion of the source text until a ‘)’ detected.
Returns:

  • true


Note:

  • Raises an XfOOrthError exception on an unterminated comment.


Endemic Code Smells

  • :reek:DuplicateMethodCall – false positive



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/fOOrth/compiler/parser/skip.rb', line 35

def skip_over_comment
  vm = Thread.current[:vm]
  vm.parens += 1

  until @source.eof?
    input = @source.get

    if input == ')'
      vm.parens -= 1
      return true
    elsif input == '('
      skip_over_comment
    end
  end

  error "F10: Unbalanced comment detected."
end

#skip_to_eolnObject

Skip over a portion of the source text until end of line detected.
Returns:

  • true



23
24
25
26
# File 'lib/fOOrth/compiler/parser/skip.rb', line 23

def skip_to_eoln
  @source.get until @source.eoln?
  true
end

#skip_white_spaceObject

Skip over any white space.
Returns:

  • The first non-white space character or nil if none were found.



12
13
14
15
16
17
18
# File 'lib/fOOrth/compiler/parser/skip.rb', line 12

def skip_white_space
  begin
    return nil unless (next_char = @source.get)
  end while next_char <= ' '

  next_char
end

#skip_white_space_or_to_eolnObject

Skip till a non-white space or an end of line



54
55
56
57
58
# File 'lib/fOOrth/compiler/parser/skip.rb', line 54

def skip_white_space_or_to_eoln
  while (next_char = @source.get)
    return next_char if (next_char > ' ') || @source.eoln?
  end
end