views:

78

answers:

2

I got an error from my Perl module "Error: Illegal declaration of subroutine". What does that mean? I tried googling for it and got the following unhelpful information:

There is a new compilation error, Illegal declaration of subroutine, for an obscure case of syntax errors.

The code which caused the error is like this (truncated to show the problem):

    $dbh->do ($stm); # ACTUAL ERROR IS THE SEMICOLON HERE
    or croak "Can't insert using '$stm': ", $dbh->errstr;
    return $dbh->last_insert_id ('', '', '', '');
}

sub insert_check # ERROR MESSAGE IS PRINTED FOR THIS LINE
{
    my ($dba, $table, $set) = @_;
+3  A: 

This is illegal Perl code: 'or' is an infix operator, so it can not start a statement.

Fix the code (or the code that generated it) by removing the ';' and the error will disappear.

dolmen
Nice sunglasses.
Kinopiko
I want one of those glasses you're wearing!
fengshaun
@fengshaun: I lost them a while ago. But my new ones are similar. We can arrange something if you go to YAPC::Europe in Pisa.
dolmen
A: 

Filling in enough of the gaps to reproduce the problem

 1  #! /usr/bin/perl
 2  
 3  use Carp;
 4  
 5  sub foo {
 6      $dbh->do ($stm);
 7      or croak "Can't insert using '$stm': ", $dbh->errstr;
 8      return $dbh->last_insert_id ('', '', '', '');
 9  }
10  
11  sub insert_check
12  {
13      my ($dba, $table, $set) = @_;
14  }

and then feeding it to the compiler, I get

$ perl5.10.1 -cw kinopiko.pl
syntax error at prog.pl line 7, near "or"
Illegal declaration of subroutine main::insert_check at prog.pl line 11.

As you can see, the first error is a result of the stray semicolon. As far as Perl's grammar is concerned, line 6 is syntactically correct.

In general, you want to begin fixing syntax errors at the first error because of a common technique for implementing parsers. Imagine working with a compiler that diagnoses only the first error it encounters. ‘I’m almost there!’ you'd think only to be disappointed by the next run—and then the next and the next and the next. To avoid frustrating users and pushing a few over the edge, parsers do their best to continue as described on page 205 of flex & bison:

Bison Error Recovery

Bison has some provisions for error recovery, which are available by using the special-purpose error token. Essentially, the error token is used to find a synchronization point in the grammar from which it is likely that processing can continue. That's likely, not certain. Sometimes attempts at recovery will not remove enough of the erroneous state to continue, and the error messages will cascade. Either the parser will reach a point from which processing can continue or the entire parser will abort.

After reporting a syntax error, a bison parser discards symbols from the parse stack until it finds a state which it can shift an error token. It then reads and discards input tokens until it finds one that can follow the error token in the grammar. This latter process is called resynchronizing. It then resumes parsing in a recovering state, which doesn't report subsequent parse errors. Once it has shifted three tokens successfully, it presumes that recovery is complete, leaves the recovery state, and resumes normal parsing.

Note that bison is involved in generating perl's parser.

If you're curious enough to dig into what whacko state the parser finds itself in after resynchronization, fire up a perl built with DEBUGGING with the -Dp or -Dpv option:

-Dletters

-Dnumber

sets debugging flags. To watch how it executes your program, use -Dtls. (This works only if debugging is compiled into your Perl.) Another nice value is -Dx, which lists your compiled syntax tree. And -Dr displays compiled regular expressions; the format of the output is explained in perldebguts.

As an alternative, specify a number instead of list of letters (e.g., -D14 is equivalent to -Dtls):

1 p Tokenizing and parsing (with v, displays parse stack)

Greg Bacon