CS 230 Programming Languages 09 / 16 / 2013 Instructor: Michael Eckmann
Today s Topics Questions/comments? Continue Syntax & Semantics Mini-pascal Attribute Grammars More Perl
A more complex grammar Let's take a look at the handout for the mini-pascal language. Let's first randomly generate a valid sentence (program) or two given this description. Then let's in our mind sort of create a parser from this EBNF description and use that to determine if some programs are syntactically correct.
Limitations of CFG and EBNF Do you think that the EBNF for mini-pascal is the complete description for the syntax of the language? Is anything missing? --- think of some syntax errors that you are used to seeing in your favorite language.
Attribute Grammars Hence the creation of attribute grammars. An attribute grammar is an extension to a CFG. There are some rules of programming languages that cannot be specified in BNF (or by a CFG for that matter.) e.g. All variables must be declared before they are used. Also, there are things that are possible, but just too hairy to specify using CFG's, (e.g. Type compatibility) so Attribute Grammars are used. These kinds of things are termed static semantics. This is a bit of a misnomer because they are really still syntax rules not semantics.
Attribute Grammars An attribute grammar is a CFG (S, N, T, P) with the following additions: For each grammar symbol x there is a set A(x) of attribute values Each production (rule) has a set of functions that define certain attributes of the nonterminals in the production Each production has a (possibly empty) set of predicates to check for attribute consistency Proposed by Knuth in 1968. In practice (e.g. Actual compilers) attribute grammars are not generally used in a formal way, but the concepts are most definitely incorporated in compilers.
Attribute Grammars The example on page 136 shows the use of an attribute grammar to enhance the BNF of an assignment statement with rules that specify the allowable types (int / real) that can be assigned to each other. e.g. A real (float) cannot be assigned to a variable whose type is int and an int cannot be assigned to a real. Also, the example shows how one can determine the resulting type of an expression.
Attribute Grammars I'm not concerned with us knowing all the ins and outs of attribute grammars, but what is important are the general concepts involved and the intended purpose of them. Attribute grammars are generally not used in practice for a few reasons. Can you guess them?
Attribute Grammars Attribute grammars are generally not used in practice for a few reasons. Can you guess them? Size and complexity of the grammar will be high for a typical modern programming language The many attributes and rules that need to be added cause the grammar to be difficult to read and write, formally The attribute values during parsing would be costly to evaluate (the way it is described in the text.) So, in practice less formal ways are used to check for static semantics at compile-time but the ideas are the same.
Example of how Perl programmers use this short circuit feature to their advantage to make concise readable code. open(filehand, <, $fname) or die can t open file.\n ; Because of the short circuit, the above works in the following way, the open function returns false if the file can t be opened. If that happens the die function is called (see the or operator) which prints the error to STDERR and kills the program. If the file can be opened, then true is returned (but not captured in anything and hence ignored) and the or part is not evaluated (executed.)
Open and die are two of Perl s built-in functions. STDIN, STDOUT, and STDERR are file handles that are automatically available and open in Perl programs. STDIN is the keyboard and the other 2 are the console. We ll come back to more about opening files later, let s instead continue with our discussion of more operators.
if, elsif, else structures (notice the odd spelling of elsif --- there is no e in it.) Why do you think? As expected, the elsif and else portions of the if structure are optional. You can have an if, followed by zero or more elsif s, followed by zero or one else s. Also, there s an unless that can be used instead of the if (but still can use the elsif s and else portions.) unless reverses the test if you had used if
if ($count < 10) { # do something here } Is the same as: unless ($count >= 10) { # do something here }
(example of if/elsif/else) if ($count < 10) { # do something here } elsif ($count >100) { # do something here } else { # do something here }
Previous slides showed how to use if and unless on blocks of code. Interestingly, if, unless, while, until and foreach can all be used as modifiers to a simple statement. Examples: print Hello unless $printing_is_off; $total++ if $increase_total;
while, until, foreach and for are looping structures in Perl. while and for act as you d expect from knowing C++ or Java. until executes its loop until the condition becomes true, whereas while executes its loop until the condition becomes false. It s redundant. So much of Perl is. There's more than one way to do it.
foreach works on list data (e.g. arrays.) Example: foreach $element (@people) { print $element is a person in the array\n ; } # foreach iterates through all values of the array in the parens and uses the variable just after the word foreach to temporarily store the value. Then the code in the { } s executes once for every element of the array. Note: $element and @people are user-defined names (not special to Perl) Create a perl program now that has an array and prints it using code similar to above.
open( INDATA, <, datafile.txt ) or die can t open datafile.txt ; Alternatively, one can combine the mode with the file name in one string: e.g. <datafile.txt Modes: < is input, > is output (writing), >> is append, +< is read-write (assumes file exists) and >+ is read-write (file might not exist).
Another thing to notice about Perl is that for calling the built-in functions we can use parentheses around the arguments or not use the parentheses. e.g. open(fh, <data.txt ); open FH, <data.txt ; # both are valid and do the same thing. But be careful with something like: print ( 7 + 3 ) * 2; # this will cause the parens to enclose the args # and therefore it would print 10 not 20. We would want this instead: print (( 7 + 3 ) * 2);
Use the angle brackets to read a line from a file handle. Use print to write to a filehandle. e.g. print FH A line to be written to file\n ;
When reading lines from STDIN or a file, the line will contain a \n at the end. It is often the case that you wish to get rid of it. Use chomp function to do this. $inline = <STDIN>; chomp($inline); Or chomp($inline = <STDIN>); Chomp removes the end of record marker and returns the # of chars removed. chop is also a function. It removes the last character regardless if it is \n or not and returns the character.
Perl allows chaining of assignments like: $num1 = $num2 = $num3 = 0; # 0 is assigned to num3, then num3 to num2 An interesting thing about return values: The assignment operators are interesting in that they return the variable on the LHS of the assignment as an lvalue. An lvalue is something that can have a value assigned to it. ($temp -= 32) *= 5/9; # the -= in parens returns the $temp as an lvalue which is assigned # a new value with the *= assignment.
Try the following exercise: read each line of input from the file from the text file posted on our notes page. until the line that has eof is read store each line in an element of an array (with the exception of the last line eof.) store the array into a hash (can be done with one line of code) Then, in a loop, ask the user for input (from STDIN) for a product and output its price by looking it up in the hash. Do this until user enters some sentinel that you make him/her aware of at the beginning. Note: the format of the file consists of a product name on one line and its price on the next line, then another product name on the next line and it's price on the next line and so on until the last line of the file which contains the word: eof