How function calls work in Octave

GNU Octave is a numerical computation language. It’s basically a calculator with the usual functions to add, subtract, multiply and divide numbers, but with a twist: It’s really easy to do this to a lot of numbers in one swoop. Think “spreadsheet”, but with a much powerful user interface. Spreadsheets have their purpose but a lot of people use LibreOffice Calc for calculations that are much easier to do in Octave (or GNU R), they just don’t know better.

Okay, now that we know each other it’s time to get down and dirty and I mean it. I will describe the overall internal mechanics of calling a user defined function. In other words, if you have a function file called myfunc.m and you write:

myfunc ("hello world");

what happens inside the GNU Octave interpreter? This article is aimed at people knowledgeable in C++ programming. No knowledge of interpreters needed.

First, octave interprets your input and constructs a tree of the input data. This step is called parsing. When the parsing is done, we will end up with:

tree_statement_list
  tree_statement
    tree_index_expression (but tree_statement only sees the tree_expression interface)
      expr = tree_identifier ("myfunc")
      type = "("
      args = list of tree_argument_lists (yes, a list of lists)
         (0) = tree_argument_list
                 tree_constant
		   "hello world"

Mighty fine. Octave then calls the evaluation tree walker. It takes the tree and computes the actual computation the user asked for. The tree walker has a lot of friends, but one of the most important one is the symbol table. The symbol table keeps track of all variables, builtins and functions that are currently defined. It will come handy soon.

So, the tree walker sees a tree_expression and knows what to do with those. It calls the rvalue method. This method will return an octave_value with the result of ‘myfunc (“hello world”)’. But we will go even deeper and figure out what happens inside the tree_index_expression.

Rvalues, for those not familiar with programming language theory, is the “right-hand value”. These are values that can not be written to, as opposed to “left-hand values” that can be written to. Why are the referred to as right and left? It is most likely because assignments like ‘A = B(0)’, where A is lvalue and B(0) is rvalue respectively.

INSIDE RVALUE

This is when things get real. A special case in rvalue determines that the index (“hello world”) isn’t empty and the identifier (myfunc) isn’t a variable defined in this scope. So now we have to look at these two and figure out what to do. The identifier’s do_lookup function does this for us. This is what the comment says:

  // Try to find a definition for an identifier.  Here's how:
  //
  //   * If the identifier is already defined and is a function defined
  //     in an function file that has been modified since the last time 
  //     we parsed it, parse it again.
  //
  //   * If the identifier is not defined, try to find a builtin
  //     variable or an already compiled function with the same name.
  //
  //   * If the identifier is still undefined, try looking for an
  //     function file to parse.
  //
  //   * On systems that support dynamic linking, we prefer .oct files,
  //     then .mex files, then .m files.

  octave_value
  do_lookup (const octave_value_list& args = octave_value_list ())

MS Paint Adventures illustrationYes, do_lookup does all that! This is an important member function. That must be a very complicated function, right? Yes doubly so, since it turns out to be implemented with just one line. It just asks the symtab to figure out all this stuff, which has to wait until it gets an article of its own. Bottom line is, in this example, do_lookup will return an octave_user_function (in the guise of an octave_value, of course).

We are still in the tree_index_expression’s rvalue though. What happens next is that the rvalue is calculated by calling octave_user_function->subsref. (It basically does the job of the Octave-language subsref function.) Looking inside subsref, it sooner or later comes down to a tree_statement_list, and well, you know the rest.

I hope this raises some questions and increases confusion about the Octave interpreter.

Grundberg

This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.