maasha
maasha

Reputation: 1995

Compiling Ruby Inline C code - resolving errors

I am trying to get this Ruby inline C code http://pastie.org/2825882 to work. The code works in vanilla C, but here I get errors and warnings. What causes this error?

./backtrack_inline.rb:67: error: lvalue required as unary '&' operand

Also, why do I get the following error?

./backtrack_inline.rb:73: error: too few arguments to function 'backtrack'

Inspecting the resulting C code ( http://pastie.org/2826036) I fail to see anything wrong with the arguments. But I do also get the following warnings:

./backtrack_inline.rb:73: warning: passing argument 1 of 'backtrack' makes integer from pointer without a cast
./backtrack_inline.rb:73: warning: passing argument 2 of 'backtrack' makes integer from pointer without a cast
./backtrack_inline.rb:73: warning: passing argument 3 of 'backtrack' makes integer from pointer without a cast

Upvotes: 6

Views: 651

Answers (3)

maasha
maasha

Reputation: 1995

OK, the question was also answered at Ruby Forum:

http://www.ruby-forum.com/topic/2959614

Upvotes: 1

matt
matt

Reputation: 79723

Starting with this:

./backtrack_inline.rb:73: error: too few arguments to function 'backtrack'

If you look at your generated code, the backtrack function is defined on line 29:

static VALUE backtrack(VALUE self, VALUE _ss, VALUE _s, VALUE _p, VALUE _mm, VALUE _ins, VALUE _del) { ... }

It has seven arguments, the original six, plus VALUE self as it has been converted into a method on the Scan class.

The call to this function, on line 67 looks like this:

end = backtrack(ss, s, p, mm, ins, del);

It has only six arguments. RubyInline doesn't convert this to a call to a method on the object, it simply copies it verbatim. This is also where the warnings about makes integer from pointer without a cast come from: the function definition has been converted to take VALUEs, but you're calling with the original types.

The error message says that the error is from line 73 in backtrack_inline.rb because of the directive on line 54 of the generated code:

# line 61 "./backtrack_inline.rb"

which basically tells the compiler to "reset" its line and file values for errors, and treat the next line (55) as being line 61 in the file ./backtrack_inline.rb. The actual line is 67, 12 ahead of 55, but the compiler reports it as being 73, 12 ahead of 61 (the value it was reset to) and from a differnt file. This technique doesn't really work in this case as it doesn't take into account the extra lines added by RubyInline. The actual line in the source is 69.

A simple fix for this is to change the definition of the backtrack function to be just a C function rather than add it as a method on the object. Change builder.c to builder.prefix (on line 38 of your Ruby file). This won't work if you want to have backtrack available as a method on the object in Ruby. If that's the case you might need create another function to be the method, which then wraps the "real" backtrack function.

Next, looking at

./backtrack_inline.rb:67: error: lvalue required as unary '&' operand

This actually refers to line 61 of the generated code, which looks like:

char* s = StringValuePtr(rb_iv_get(self, "@seq"));

StringValuePtr is a macro which is defined as:

#define StringValue(v) rb_string_value(&(v))

This is where the & in lvalue required as unary '&' operand comes from. You need to add a local variable to be the lvalue:

VALUE seq = rb_iv_get(self, "@seq");
char* s = StringValuePtr(seq);

In my case (Mac OS X Snow Leopard, Ruby 1.9.3-p0, RubyInline 3.11.0) these two changes made the script run without errors, but gave the warning:

backtrack_inline.rb:47: warning: implicit conversion shortens 64-bit value into a 32-bit value

This actually refers to line 46 of the ruby file:

return (s - ss) - 1;

s and ss are char *, i.e. 64 bit pointers (on this machine), and the return type of the function is int - 32 bits. Adding an explicit cast fixed this:

return (int)((s - ss) - 1);

It now runs cleanly:

ruby-inline $ ruby backtrack_inline.rb 
14
ruby-inline $ 

(I hope 14 is the correct answer!)

Here's a version of the script with these changes.

Upvotes: 5

Taryn East
Taryn East

Reputation: 27747

Ok... thought a bit more about this.

you are calling a variable end. While this isn't a reserved word in C - and ruby shouldn't be looking at it... perhaps ruby is getting confused?

I'd suggest you have a go at renaming it just in case. Worthwhile trying even just to rule it out.

Upvotes: 0

Related Questions