class Parser

This is a stack-based parser that returns a tree in array format. Sub arrays are operations with higher priority. Operators are converted to symbol. It must be associated to Scp. Eg: 3 + 4 * 9 => `[3, :+, [4, :*, 9]]`

Author

Massimiliano Dal Mas (max.codeware@gmail.com)

License

Distributed under MIT license

Public Class Methods

new() click to toggle source

Initialize two new variables: a counter and a boolean one to report errors and stop the parser

# File lib/linmeric/Parser.rb, line 18
def initialize()
  @d = 0
  @error = false
end

Public Instance Methods

extract(expr) click to toggle source

Extracts the content between quotes (it must not be parsed)

  • argument: string to extract the sub-string from

  • returns: sub-string

# File lib/linmeric/Parser.rb, line 130
def extract(expr)
  ext = '"'
  while expr[@d] != '"' do
    ext += expr[@d]
    @d += 1
  end
  @d += 1
  return ext + '"'
end
parse(expr) click to toggle source

Main function that parses the string

  • argument: string to be parsed; the string must be the

output of scopify (see: Scp )

  • returns: abstract tree array

# File lib/linmeric/Parser.rb, line 34
def parse(expr)
  array = Array.new
  until @d == expr.length
    c = expr[@d]
    case c
      when "("
        @d += 1
        calc = parse(expr)
        array.push calc if calc != nil 
      when ")"
        @d += 1
        return array
      when /[\*\/]/
        @d +=1
        array.push c.to_sym
      when /[\+\-\^]/
        @d+=1
        array.push c.to_sym
      when /\=/
        @d += 1
        array.push c.to_sym
      when /\>/
        @d += 1
        array.push c.to_sym
      when /\"/
        @d += 1
        array.push extract(expr)
      when /\~/
        @d += 1
        if expr[@d] == "("
          @d +=1
          calc = parse(expr)
          array.push calc unless calc == nil
        else
          array.push expr[@d]
          @d += 1
        end
      when /\./
        if expr[@d-1] =~ /[0-9]+/
          x = array.pop.to_s + c + expr[@d+1]
          array.push x.to_n
        else
          unless @error
            @error = true
            puts "Problem evaluating expression at index:#{@d}"
            puts "Invalid char '#{expr[@d]}' in string variable"
          end
          return
        end
        @d+=2
      when /\:/
        if expr[@d - 1] =~ /[a-zA-Z]+/ then
          x = array.pop.to_s + c
          array.push x.downcase.to_sym
        else
          unless @error
            @error = true
            puts "Problem evaluating expression at index:#{@d}"
            puts "Invalid char '#{expr[@d]}' in numeric variable"
          end
          return
        end
        @d += 1
      when /\_/
        @d += 1
        x = array.pop.to_s + c
        array.push x
      when /\p{Alnum}/ 
        if expr[@d-1] =~ /[0-9]/ && array.count > 0
          x = array.pop.to_s + c
          array.push x.to_n
        elsif (expr[@d-1] =~ /[a-zA-Z]/ or expr[@d-1] == '_') && array.count > 0
          x = array.pop.to_s + c 
          array.push x 
        else 
          array.push c.to_n if c =~ /[0-9]/
          array.push c if c =~ /[a-zA-Z]/
        end          
        @d += 1
      else
        unless @error
          @error = true
          puts "Problem evaluating expression at index:#{@d}"
          puts "Char '#{expr[@d]}' not recognized"
        end
        return
    end
  end

  return array
end
reset() click to toggle source

Re initializes the counter and the boolean variable

# File lib/linmeric/Parser.rb, line 24
def reset()
  @d = 0
  @error = false
end