Class: CTioga2::Commands::InterpreterString::LexicalAnalyzer
- Inherits:
-
Object
- Object
- CTioga2::Commands::InterpreterString::LexicalAnalyzer
- Defined in:
- lib/ctioga2/commands/strings.rb
Overview
A small lexical parser. It’s job is to carry out the function of InterpreterString.parse_until_unquoted.
Instance Attribute Summary collapse
-
#current_string ⇒ Object
The current object on the way of being parsed.
-
#io ⇒ Object
The io device with which the parser is interacting.
-
#parsed ⇒ Object
The current string result, as described in InterpreterString.
-
#state ⇒ Object
The state of the parser: * :start -> first starting elements * :top -> toplevel * :single -> in a single quoted string * :double -> in a double quoted string * :dollar -> last element was a dollar at top-level * :dq_dollar -> last element was an unescaped dollar within a double quoted string * :escape -> last element was an unescaped escape char within a double-quoted string.
-
#term ⇒ Object
The terminating element.
Instance Method Summary collapse
-
#initialize(io, term) ⇒ LexicalAnalyzer
constructor
Initializes the parser.
-
#parse(eoerror = true) ⇒ Object
Parse the string from the io object.
-
#push_current_element ⇒ Object
Pushes the element currently being parsed unto the result.
Constructor Details
#initialize(io, term) ⇒ LexicalAnalyzer
Initializes the parser.
73 74 75 76 |
# File 'lib/ctioga2/commands/strings.rb', line 73 def initialize(io, term) @io = io @term = term end |
Instance Attribute Details
#current_string ⇒ Object
The current object on the way of being parsed
64 65 66 |
# File 'lib/ctioga2/commands/strings.rb', line 64 def current_string @current_string end |
#io ⇒ Object
The io device with which the parser is interacting.
67 68 69 |
# File 'lib/ctioga2/commands/strings.rb', line 67 def io @io end |
#parsed ⇒ Object
The current string result, as described in InterpreterString
61 62 63 |
# File 'lib/ctioga2/commands/strings.rb', line 61 def parsed @parsed end |
#state ⇒ Object
The state of the parser:
-
:start -> first starting elements
-
:top -> toplevel
-
:single -> in a single quoted string
-
:double -> in a double quoted string
-
:dollar -> last element was a dollar at top-level
-
:dq_dollar -> last element was an unescaped dollar within a double quoted string
-
:escape -> last element was an unescaped escape char within a double-quoted string.
-
:var -> in a $(variable)
-
:dq_var -> in a $(variable) within a double-quoted string
58 59 60 |
# File 'lib/ctioga2/commands/strings.rb', line 58 def state @state end |
#term ⇒ Object
The terminating element
70 71 72 |
# File 'lib/ctioga2/commands/strings.rb', line 70 def term @term end |
Instance Method Details
#parse(eoerror = true) ⇒ Object
Parse the string from the io object
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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/ctioga2/commands/strings.rb', line 79 def parse(eoerror = true) @state = :start @parsed = [] @current_string = '' i = -1 while(1) c = @io.getc if ! c # EOF if eoerror raise UnterminatedString, "EOF reached before the end of this string" else push_current_element return @parsed end end # Convert the integer to a string. ch = c.chr i += 1 if (@state == :start || @state == :top) and (term.include?(ch)) # Finished push_current_element @io.ungetc(c) # We push back the last char. return @parsed end # puts "#{@state.inspect} -- #{ch}" # We skip white space at the beginning of the string. if @state == :start # Skip white space if ! (ch =~ /\s/) @state = :top end end case @state when :escape # Evaluating escape chars @current_string += eval("\"\\#{ch}\"") @state = :double when :dollar, :dq_dollar @state = (@state == :dollar ? :top : :double) if ch == '(' # Beginning of a variable within a # quoted string push_current_element @state = (@state == :top ? :var : :dq_var) else @current_string += "$#{ch}" end when :single # The simplest string if ch == "'" # End of string push_current_element @state = :top else @current_string += ch end when :var, :dq_var if ch == ")" push_current_element @state = (@state == :var ? :top : :double) elsif ch =~ /\s/ # We don't have a variable, but a function... @accessory = InterpreterString.parse_until_unquoted(@io, ")", true) ch = @io.getc # Slurp the closing ) ns = (@state == :var ? :top : :double) @state = (:var ? :funcall : :dq_funcall) push_current_element @state = ns ## @todo Optional: instead of having a space, use a , ## or . or # to signify different separators ? (but ## quoting makes this more-or-less unnecessary, hey ?) else @current_string += ch end when :top if ch == "'" # We start a single-quoted string push_current_element @state = :single elsif ch == '$' # Dollar state @state = :dollar elsif ch == '"' push_current_element @state = :double elsif ch == '#' # A comment: we read until end-of-line @io.gets # and ignore the results else @current_string += ch end when :double if ch == '"' # (necessarily unquoted) push_current_element @state = :top elsif ch == '$' @state = :dq_dollar elsif ch == "\\" @state = :escape else @current_string += ch end end end end |
#push_current_element ⇒ Object
Pushes the element currently being parsed unto the result
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/ctioga2/commands/strings.rb', line 186 def push_current_element if @current_string.size == 0 return end case @state when :top # We push an unquoted string @parsed << [:unquoted, @current_string] when :single, :double @parsed << [:quoted, @current_string] when :var @parsed << [:unquoted_variable, @current_string] when :dq_var @parsed << [:quoted_variable, @current_string] when :funcall @parsed << [:unquoted_funcall, @current_string, @accessory] when :dq_funcall @parsed << [:quoted_funcall, @current_string, @accessory] when :dollar @parsed << [:unquoted, @current_string + '$'] when :dq_dollar @parsed << [:quoted, @current_string + '$'] when :escape @parsed << [:quoted, @current_string + "\\" ] when :start # Empty string at the beginning. Nothing interesting, move # along ! else raise "Fatal bug of the lexical analyzer here : unkown state" end # Flush current string @current_string = "" end |