Perl syntax compile error - perl

Here is a bit of code from a program I'm writing, the syntax error lays in the 3rd line.
if($header gt $word{
$wordlist{$word} = $header;
$header = $word;
return;
}

In short - you're missing a closing parenthesis on the first line
It's quite funny actually because you'd expect Perl to point you to the right location with its error message. However, due to a stroke of bad luck it seems just like the beginning of a perfectly valid code that just happens to do something else than what you intended.
Perl actually thinks you look up a hash called %word (using $word{...} with the value of the assignment evaluated as key).
So, this would have been a perfectly valid code if you'd have done this:
if ($header gt $word{
$wordlist{$word} = $header # removed the ;
}) { # closed the condition
$header = $word;
return;
}
Perl is only confused once it reaches the end of the second line and sees the ;

Related

How do I compare two strings using Perl

I have googled until I ran out of options. I must be doing something wrong but I cannot figure out what. (obviously I am new to Perl and inherited this project).
I am just trying to see if a variable is equal to 'Y'. As you can see towards the bottom of the code below, I have tried 'eq', '=' and '=='. Other than setting a new variable equal to the result of an 'eq' operation, all the attempts result in the page blowing up. The result of the string test ($stringtest) appears to be empty and I would not know how to test it if it wasn't.
#!/usr/bin/perl -w
#######################################################################
# Test script to show how we can pass in the needed information
# to a web page and use it to run a program on the webserver and
# redirect its output to a text file.
#######################################################################
require 5; #Perl 5 or greater
require "jwshttputil.pl";
require "jwsdbutil.pl";
# Parse QUERY_STRING
&HTTPGet;
# Parse POST_STRING - NOTE: This CLEARS the post data
&HTTPPost;
print STDOUT "Content-type: text/html\n\n";
print STDOUT "<HTML><BODY>";
$canrun = "Y";
$is4ge = $Data{'is4ge'};
$sYes = "Y";
#Step 1: Check for needed values
if ( !($Data{'user'}) )
{
print "user was not found<br/>";
$canrun = "N";
}
if ( !($Data{'pwd'}) )
{
print "pwd was not found<br/>";
$canrun = "N";
}
if ( !($Data{'is4ge'}) )
{
print "is4ge was not found<br/>";
$canrun = "N";
}
print "$Data{'is4ge'}"; #prints Y
print $is4ge; #prints Y
if ( !($Data{'db'}) )
{
print "db was not found<br/>";
#if (!($is4ge = "Y")) #dies
# $canrun = "N";
#if (!($is4ge eq "Y")) #dies
# $canrun = "N";
#$stringtest = ($is4ge eq $sYes);
#print $stringtest; #displays nothing
#if (($is4ge == $sYes)) #dies
# $canrun = "N";
}
print STDOUT "</BODY></HTML>";
You have a good answer to your question, but it might be useful to point out how you could have investigated this yourself.
Firstly, your original title for this question was "How do I compare two strings in a CGI page under Apache?" That title has been corrected because this problem has nothing to do with CGI or Apache, it's simply a misunderstanding about Perl syntax. I know you couldn't have known that initially, but a good way to investigate strange errors like this is to eliminate as many of the complications as possible. So forget about CGI and web servers - just write a simple Perl program.
#!/usr/bin/perl
$canrun = 'N';
$is4ge = 'Y';
if (!$is4ge eq 'Y')
$canrun = 'Y';
print $canrun;
Running this, we get:
$ perl testif
Scalar found where operator expected at testif line 7, near ")
$canrun"
(Missing operator before $canrun?)
syntax error at testif line 7, near ")
$canrun "
Execution of testif aborted due to compilation errors.
That makes it clear that the problem is the syntax around lines 6 and 7. That might be enough to send you off to the Perl syntax manual page, where you would learn that condition statements in Perl always require braces around the block. If not, you could add the diagnostics pragma to get more information.
So as you've already been told, the correct format for your test is
if ($is4ge ne 'Y') {
$canrun = 'Y';
}
But there are a few other things in this program that will make it hard to maintain in the future. Basically, it is rather falling behind with Perl best practices.
You use -w when that was replaced with use warnings in Perl 5.6.0 (released in 2000)
You don't have use strict in the code (that will point out many bad practices in your code which you'll want to fix - in particular, you'll need to declare your variables).
The two libraries that are required at the top of the program might well be better rewritten as proper Perl modules.
I worry that jwshttpdutil.pl might be a home-baked CGI parser that should be replaced with CGI.pm.
The embedded HTML in the code should be replaced with a templating engine of some kind.
Also, I recommend reading CGI::Alternatives to bring yourself up to date with modern Perl methods for writing web applications. You are using techniques that were out of date before the end of the last millennium.
Curlies around the body of flow control statements are not optional in Perl.
eq is indeed the string comparison operator in Perl.
So,
if (!($is4ge eq "Y")) {
$canrun = "N";
}
Or just
if ($is4ge ne "Y") {
$canrun = "N";
}
You really should be using 1 and 0 instead of 'Y' and 'N', since they are true and a false values that can more easily be tested.

Perl: Error printing after do-while loop

I am making a concatenating do-while loop wherein each of the entered strings will be added to the main string $food. Here is the code:
do {
print("\nEnter your order(-1 to end): ");
$order = <>;
chop($order);
if ($order != -1) {
$food .= " ".$order;
print($food);
}
} while ( $order != -1)
print ($food); #PROBLEM HERE!
The problem is that whenever I put print ($food) outside the loop, a syntax error for this line appears plus an Execution of file.pl aborted due to compilation errors message.
The code works once I put print ($food) inside the loop but I am curious to why this error is happening.
Your line before last print has syntax error - it does not end with ;.
Just add it and it should work.
A thing worth mentioning in addition to the syntax error: I see that you you start the string with a newline. While this is fine, it might be considered "better" to end strings with the newline before printing, as printing a newline would result in flushing the STDOUT buffer right away. In most cases, this is the behavior you want, as it prevents delayed output and text flickering (especially if printing a lot).

Perl Global variable uninitialized

I'm new to perl so please bear with me.
I have script that is parsing a CSV file. To make things easier to debug I am using a state machine FSA::Rules (works great love it).
Every thing is going well only now I need to make my logs make sense, as part of this I need to record line numbers so my program looks some thing like this.
my $line = '';
my $lineCount = 0;
sub do {
...
#CSV opened
...
#State machine stuff happens here
readLine;
if ($line =~ m/.*Pattern*/){
#do stuff
}
}
sub readLine{
$line = <CSV>;
$lineCount ++;
}
But I get the following error
Use of uninitialized value $line in pattern match (m//) at
Any one know why $line would not be initialized?
Thanks.
When you reach end of file, $line = <CSV> will assign the undefined value to $line. The usual idiom is to check whether the readline function (which is implicitly called by the <> operator) returned a good value or not before proceeding ...
while (my $line = <CSV>) {
# guaranteed that $line has a defined value
...
}
but you with your sequence of calls, you are avoiding that check. Your current code also increments $lineCount even when <CSV> does not return a good value, which may not be what you want either.

Perl while loop / reading file

I'm new to Perl and I have a problem when reading a file line by line. I started with a tutorial which suggested using a while loop. That worked fine, however I wanted to have an option to break out of the loop in case of an error. I know I can use the "last" keyword, but I don't like that very much, I would like to include it in the while loop's boolean expression so it is easier to see on what conditions it stops. So I did
$error=0;
while ( (!$error) && (<MYFILE>) ) {
print $_;
...
}
Unfortunately, this doesn't work because $_ seems to contain a "uninitialized value". For some reason, when I change (!$error) to (!0), it works again. I would understand that it was not working had I used || because of lazy evaluation, but with && in this case both sides need to be evaluated so I don't understand why it doesn't initialize the line variable.
The magical assignment to $_ only occurs if there is nothing else in the loop:
while (<MYFILE>) {
print $_;
...
}
If you want the error test too - which is not recommended - then you need to do the assignment:
my $error = 0;
while (!$error && ($_ = <MYFILE>)) {
print;
$error = 1 if m/quit/i;
}
Don't forget to add:
use warnings;
use strict;
The reason why the version with '!0' worked is probably because Perl optimizes and recognizes that '!0' is always true and removes it from the loop, leaving just the I/O operator, which then assigns to $_.
NB: it is far better to use idiomatic Perl and the last statement:
while (<MYFILE>) {
print;
last if m/quit/i;
}
First, as Jonathan points out you should always write languages idiomatically unless you have a very good reason and here you don't.
Your larger problem is misunderstanding the while loop. The automatic assignment of the result of the angle operator to $_ only occurs if it is the only thing in the while conditional test. If there are multiple items in the conditional test they are evaluated and then discarded (Programming Perl pp. 80-81 and I/O Operators at Perldoc).

code working fine on Perl 5.12.1 doesn't work on 5.10.0

I wrote some code (about 100 lines) that is working fine on version 5.12.1.
Unfortunately my client is using version 5.10.0. So I tested the code on 5.10.0 and found it doesn't work!
Where can I find a list of differences between 5.10 and 5.12?
Edit:
I think the best answer to the question of "Where can I find a list of differences between 5.10 and 5.12" is plusplus' comment under the "accepted answer". For the explanation of the code below, please read Michael Carman's answer.
The code that works on 5.12.1 but does not work on 5.10.0 ($contents is still an empty string after running the code)
# read in the first 10 lines.
my $contents = '';
for (my $i = 0; $i < 10 && ! eof; $i++) {
$contents .= <FILE>;
}
The improved code that works on both versions.
# read in the first 10 lines.
my $contents = '';
my $i = 0;
while (<FILE>) {
last if $i >= 10;
$contents .= $_;
$i++;
}
There's a bug in your first code sample. A bare eof reports status for the last filehandle read. On of the first pass through the loop you (presumably) haven't read anything yet; not anything from FILE anyway. It appears that the internal behavior of this invalid call changed. Under Perl 5.12.1 running perl -E "say eof" prints nothing. Under Perl 5.10.0 it prints "1".
Explicitly testing eof(FILE) should fix the problem.
Tangent: Your code isn't very idiomatic. A more perlish approach would be
my $content;
while(<$fh>) {
if ( 1 .. 10 ) { $content .= $_ }
else { last }
}
The idioms used are:
Use a lexical filehandle instead of a typeglob. ($fh instead of FILE)
Use the range operator .. to track the number of lines read. This form
implicitly tests against the input line number $..
Don't explicitly test for EOF (let the loop handle it).
Use last to break out of the loop early.
Look at the perldoc page. You''ll find the perldelta's there. Or post your code and have us look at it ;)