1
# file.rb: a file parser for ctioga2
2
# copyright (c) 2009 by Vincent Fourmond
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details (in the COPYING file).
15
require 'ctioga2/utils'
17
require 'ctioga2/commands/commands'
18
require 'ctioga2/commands/strings'
22
Version::register_svn_info('$Revision: 151 $', '$Date: 2010-06-19 23:45:20 +0200 (Sat, 19 Jun 2010) $')
28
# Raised when EOF is encountered during a symbol parsing
29
class UnterminatedSymbol < Exception
32
# Unexepected character.
33
class UnexpectedCharacter < Exception
37
class ParserSyntaxError < Exception
40
# This class is in charge of parsing a command-line against a list
46
# Runs a command file targeting the given _interpreter_.
47
def self.run_command_file(file, interpreter)
48
FileParser.new.run_command_file(file, interpreter)
51
# Runs the given command strings
52
def self.run_commands(strings, interpreter)
53
FileParser.new.run_commands(strings, interpreter)
56
# Runs a command file targeting the given _interpreter_.
57
def run_command_file(file, interpreter)
59
parse_io_object(f, interpreter)
62
# Runs the given command strings
63
def run_commands(strings, interpreter)
64
io = StringIO.new(strings)
65
parse_io_object(io, interpreter)
68
# Parses a given _io_ object, sending commands/variable
69
# definitions to the given _interpreter_.
70
def parse_io_object(io, interpreter)
71
# The process is simple: we look for symbols and
72
# corresponding syntax element: parentheses or assignments
74
symbol = up_to_next_symbol(io)
80
raise ParserSyntaxError, "Expecting something after symbol #{symbol}"
83
if ch =~ /\s/ # blank...
85
elsif ch == '(' # beginning of a function call
87
str = InterpreterString.parse_until_unquoted(io,")")
88
# Now, we need to split str.
89
args = str.expand_and_split(/\s*,\s*/, interpreter)
91
cmd = interpreter.get_command(symbol)
92
real_args = args.slice!(0, cmd.argument_number)
93
# And now the options:
96
# Problem: the space on the right of the = sign is
99
if o =~ /^\s*\/?([\w-]+)\s*=(.*)/
100
if cmd.has_option? $1
104
"Command #{cmd.name} does not take option #{$1}"
110
interpreter.run_command(cmd, real_args, options)
111
io.getc # Slurp up the )
113
elsif ch == ':' # Assignment
116
raise ParserSyntaxError, "Expecting = after :"
120
raise ParserSyntaxError, "Expecting = after :"
122
str = InterpreterString.parse_until_unquoted(io,"\n", false)
123
interpreter.variables.define_variable(symbol, str,
127
str = InterpreterString.parse_until_unquoted(io,"\n", false)
128
interpreter.variables.define_variable(symbol, str, nil)
131
raise UnexpectedCharacter, "Did not expect #{ch} after #{symbol}"
139
SYMBOL_CHAR_REGEX = /[a-zA-Z0-9_-]/
141
# Parses the _io_ stream up to and including the next
142
# symbol. Only white space or comments may be found on the
143
# way. This function returns the symbol.
145
# Symbols are composed of the alphabet SYMBOL_CHAR_REGEX.
146
def up_to_next_symbol(io)
148
symbol = nil # As long as no symbol as been started
154
raise UnterminatedSymbol, "EOF reached during symbol parsing"
156
# File is finished and we didn't meet any symbol.
162
if symbol # We have started
163
if ch =~ SYMBOL_CHAR_REGEX
170
if ch =~ SYMBOL_CHAR_REGEX
177
raise UnexpectedCharacter, "Unexpected character: #{ch}, when looking for a symbol"