Newbie Question: - Parse my commands...

P

paytonrules

Okay I'm trying to take our old scripting software and quickly move it
up in the world. We have a program that takes as a parameter a script
file, parses it and runs it for unit testing purposes. There are
several problems:

1) Each script file requires setting up a large database.
2) No way to debug a file short of setting breakpoints in C++ on the
parser itself.
3) No way - this is the big one - to just run an individual command
and get instant feedback.

Now in the meantime I've been playing with Ruby and ROR and I think I
should be able to use the irb command to create this pretty quickly,
but I'm not quite sure how. Our commands in the .scr file currently
look like this

ObjectName.Make(param1, param2, param3, param4)

The first step, which I'm doing now, is to take our executable program
and break the parsing engine into a DLL. That's easy. I can then
create a quick ruby program so I could do this:

irb
load 'rubyProg'

parse ObjectName.Make(param1, param2, param3, param4)


The rubyProg could work this way - but I'm pretty sure I can go one
step farther with ruby and just type:

ObjectName.Make(param1, param2, param3, param4)

through ruby extensions. The question is - how do I have the
interpreter pass on any code to the parser ruby can't handle it?
 
V

Vidar Hokstad

paytonrules said:
The first step, which I'm doing now, is to take our executable program
and break the parsing engine into a DLL. That's easy. I can then
create a quick ruby program so I could do this:

irb
load 'rubyProg'

parse ObjectName.Make(param1, param2, param3, param4)


The rubyProg could work this way - but I'm pretty sure I can go one
step farther with ruby and just type:

ObjectName.Make(param1, param2, param3, param4)

through ruby extensions. The question is - how do I have the
interpreter pass on any code to the parser ruby can't handle it?

method_missing() can be used for this to some extent. It depends on how
exact you want the syntax. If you can get away with changing the object
names so that they start with a lowercase letter it's cleaner. In Ruby,
a capital first letter of a name indicates a constant, which means you
need some extra uglyness to handle that.

With a lowercase first letter in your object names you can do:

class MissingProxy
def initialize ob
@ob = ob
end

def method_missing(sym,*args)
# Call your script processor here.
puts "PROCESS: #{@ob.to_s}.#{sym.to_s}(#{args.join(',')})"
end
end

def method_missing(sym,*args)
MissingProxy.new(sym)
end

myObject.Make('test',123)


If, on the other hand you don't want to rewrite anything, you can wrap
the statements like this:

begin
MyObject.Make('test',123)
rescue NameError => n
eval("#{n.name} = MissingProxy.new:)#{n.name})")
retry
end

I'd consider both of these methods fairly ugly. They make trapping
errors in your Ruby code tricky, as any misspelled object/class names
will trigger your script interpreter instead of giving an error, but it
does give a lot of flexibility.

An alternative that is less intrusive is to wrap the latter method
missing in a module:

module Script
def method_missing(sym,*args)
MissingProxy.new(sym)
end
end

And add the module name to any script command:

Script.MyObject.Make('test',123)

If you do it this way at least misspellings etc. in your Ruby code is
less likely to trigger your script processing, but then I guess you
could just as well do it the way you suggested in the first place.

Vidar.
 
L

Logan Capaldo

method_missing() can be used for this to some extent. It depends on how
exact you want the syntax. If you can get away with changing the object
names so that they start with a lowercase letter it's cleaner. In Ruby,
a capital first letter of a name indicates a constant, which means you
need some extra uglyness to handle that.

With a lowercase first letter in your object names you can do:

class MissingProxy
def initialize ob
@ob = ob
end

def method_missing(sym,*args)
# Call your script processor here.
puts "PROCESS: #{@ob.to_s}.#{sym.to_s}(#{args.join(',')})"
end
end

def method_missing(sym,*args)
MissingProxy.new(sym)
end

myObject.Make('test',123)


If, on the other hand you don't want to rewrite anything, you can wrap
the statements like this:

begin
MyObject.Make('test',123)
rescue NameError => n
eval("#{n.name} = MissingProxy.new:)#{n.name})")
retry
end
To handle the MyObject case, you needs simply define const_missing
instead of method_missing, no need to rescue name error.
I'd consider both of these methods fairly ugly. They make trapping
errors in your Ruby code tricky, as any misspelled object/class names
will trigger your script interpreter instead of giving an error, but it
does give a lot of flexibility.
Agreed.
 
P

paytonrules

Logan said:
To handle the MyObject case, you needs simply define const_missing
instead of method_missing, no need to rescue name error.

I agree - but the C++ parser is allowed to return errors no?

To put it another way - lets assume I do the const_missing. Parse will
return errors - couldn't I use the parse errors to deterimine "is this
a parse error or is this a Ruby error"?

I realize I'm not explaining myself well - perhaps because I'm really
just experiementing with this to make sure I've got a good idea. We've
already got an old parser executable that parses script files. I just
want to use irb and ruby to glue this and make a statement-by-statement
runtime interpreter. Would a better design be to include the irb in my
application and work the other way around?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top