Awk# expands the Small Awk language with new statements, arrays, and functions. This gives a programmer much more flexibility and allows a programmer to create more complex scripts quickly.
Awk# programs cannot be tested currently because there is no available interpreter.
Like awk, Awk# is designed for processing data files. It works with simpler files than awk however. Awk# assumes that it will read a single file and each line in the file is a list of "fields" of data separated by one or more spaces or tabs. Smallawk reads the input file and produces a single stream of output by processing the input. Notice that a Awk# program does not start until it is given some data, and doesn't stop until it gets the usual end-of-file. Here is a traditional simple program in Awk#:
END{ print "hello, world"; }It reads the input and at the end
of the inpoyut data it outputs the "hello, world message. The following
program reads the input file and numbers the lines: { print NR, $0; }
The next program prints outs lines that contain the string "AWK":
/AWK/{ print ;}
The next program Assumes that each line has one number, and at the end of the file outputs the total of these nunmbers:
{sum = sum + $0;} END{print sum;}
This one checks the input and only adds a line if it is a valid integer, with one or more decimal digits:
/^[0-9][0-9]*$/{sum = sum + $0;} END{print sum;}
This reads in a file of names, student_ids, and scores and calculates the mean score. It assume input with data separated by spaces like this:
ShortName 9999 3.2
AnotherName 1234 17The program is
{sum = sum + $3; count=count+1;} END{print sum/count;}
Lexemes
awk# has the normal lexical scan separating
variables, constants, strings, from some reserved words:
Programs
A program is a number of global declarations, a number of function definitions, and a sequence of pieces. Each piece has two
parts: a pattern and an action. The pattern states when the action is to
be applied. When awk# is running it takes each line and tries each
piece of the program in turn and carries out the actions with patterns
that match the line.
/* Global declarations */
a = 3;
const c = 5;
/* Function definitions */
function func1()
{
return (5 + a);
}
/* Program Pieces- Activated when the pattern is matched within a line in the file. */
BEGIN
{
print func1();
}
Patterns
/Botting/||/Dick/
/Botting/ && /Richard/
!/Blotting/
/Banana/
/[bB]anana/
/^\.As_is/
/^[0-9]*$/
^.As_is
two part:$
^Dick.*Botting$
pos*ibil*ity
The "*" means "zero or more of". The above matches "posssibity" for example.
Actions
An action is a series of at least one statement. These are executed one after another.
Statements
Awk# includes a number if statements to allow the programmer flexibility in writing code.
sum = sum + $0;
a[5] = a[3] - 1;
const Sunday = 1;
print sum;
goto Lbl1;
if ( sum > 0 ) print "greater";
switch(val)
{
case 1:
print "This is Case 1;
break;
case 2:
print "This is Case 2;
break;
default:
print "EMPTY";
break;
}
for(count=0; count<=100; count=count+1)
{
print count;
}
while( EndOfFile!=true )
{
print fileValue;
}
forever
{
x=x+2;
if(x>50) break;
}
Operations
Awk# contains operation precedence so there is no confusion of which operation should be evaluated first. The operations with highest precedence to the lowest precedence are: !, *, /, %, +, -, <, <=, >, >=, ==, !=, &&, ||.
x = 5 + 2 < 12 && 8 == 4; /* x = false */
In the example, x will equal the value false. First the + is evaluated,
making the equation, 7 < 12 && 8 == 4. Then the < is evaluated, making
the equation, true && 8 == 4. Then == is evaluated, making the equation,
true && false. Lastly, the && is evaluated, returning the value false.
Expressions
Functions
exp(5,3);
function Func1(a,b)
{
c= a + b;
return c;
}
function Func2()
{
print "Hello";
return;
}
Variables and Arrays
stats[3]
stats
$0
$5
sum
Constants
Program Diagram:
Pattern Diagram:
Character Diagram:
Statement Diagram:
Loop Diagram:
Expression Diagram:
A program P will consist of a sequence of n pieces p[1]..p[n]. Each piece 'p'['i'] has two parts a pattern 'p'['i'].pattern and an action 'p'['i'].action. Here is a C++ like description of what the program P does.
>if( p[i].pattern is "BEGIN" )
apply p[i].action;
NR=1;
while( get next line until end of input )
{for(i = 1; i<=n; i++)
if( line matches p[i].pattern )
apply p[i].action to line;
NR++;
}
//after end of file
for(i = 1; i<=n; i++)
if( p[i].pattern is "END" )
apply p[i].action;
A line matches a pattern according to the rules of regular expressions on Unix systems. You can find the rules of regular expressions at: http://www.csci.csusb.edu/dick/samples/regular_expressions.html
Applying an action to the line starts by assigning the whole line to
variable $0. Then each field in the line (separated by one or more
spaces) is assigned to $1 thru to NF
where NF is set to the number of fields. An action is a sequence of
one or more instructions and these are executed in turn. If an instruction
is an assignment then the expression on the right hand side is evaluated and
the resulting value is placed in the variable on the left hand side of the
'=' sign. This may change the whole line or any field in the line if the
variable is '$0' or 'i'
for some other i. If the action is a print command with an expression then
the expression is evaluated and output plus a new line. If it is a print
with no expression then the whole line (with any changes) is printed. Expressions are evaluated in the usual way: constants become their values,
variables return their current value.
Comments
Awk# has the ability of quoting strings of sentences without the compiler parsing the phrase as an expression. This ability will allow the developer to add descriptions of programs between his statements that will describe the behavior of his expressions. Comments can also be added between functions and pieces as well. These comments can be single or multi line and the compiler will ignore anything between the symbols /* and */ :
Example:
/* The start of the program */
BEGIN
{
/*
an instance of a scalar type
*/
i = 5;
}
Our example demonstrates the usage of comments that are defined in the XBNF. We have a /* */, and everything defined between those two symbols will be ignored by the compiler.
Awk# comes with several predefined mathematical functions that it inherited from Smallawk: sin, cos, log, exp, sqrt. Because there is no way to explicitly declare a certain type of variable, Awk# provides several functions to convert a variable to a specific type: CInt, CFloat, CBool, Cstring, CChar, CLong. A variable's type is determined when it first is assigned a value. When a variable is assigned a value with a type different than its original, the variable type will change. Since a variable can hold any type, the following functions can be used to see what type the variable holds: IsInt, IsFloat, IsBool, IsString, IsChar, IsLong. Two other helpful predefined functions that are not in Smallawk, but are in Awk#, are GetChar and GetInput. GetChar returns one char from keyboard input. GetInput returns a string of input from the keyboard. Keyboard input for GetInput ends when the enter button is pressed.
Example using some predefined type functions:
BEGIN{
x= 23.4;
if (IsFloat(x)) print "X is a float";
x = CString(x);
if (IsString(x)) print "X is now a string";
}
In this example, x is assigned a float value, making it a float type. X is then tested with the function IsFloat, which returns true because x is a float. Then CString is used on x and returns the string value "23.4" which is then assigned x. IsString is then used to test to see if x is a string. Since x was assigned the string value of "23.4", x is now a string variable, meaning that IsString will return true.
Another example using predefined input functions:
BEGIN{
print "What is your name?";
name = GetInput();
print name + " do you like ice cream? (y/n)";
answer = GetChar();
if ((answer == "y") || (answer == "Y"))
print "That's great!";
else
print "That's too bad";
}
In this example, the program asks for a person's name. Once entered, the program asks whether the person likes ice cream. If the y key is pressed, the "That's great!" message will be displayed. If any other key is pressed the "That's too bad" message will be shown.
Awk# allows a programmer to define their own functions. Because there are no explicitly declared variable types in Awk#, it is not necessary to put the return type in the function definition. A function definition consists of a function name, a list of parameters, a block of statements, and a return statement within the block. Currently, variables can only be passed by value. If the function acts like a procedure, it is not necessary for the return statement to contain a value.
Within an Awk# program, all function definitions should be first, then any other statements can follow. Once a BEGIN, an END, or normal program piece occurs in the code, there can be no other functions definitions or an error will occur. Functions can also not be defined in other functions or within any other blocks.
Examples of function definitions:
function Func1(a,b)
{
c= a + b;
return c;
}
function Func2()
{
print "Hello";
return;
}
Func1 is an example of a typical function definition. Func1 contains the parameters a and b, passed in by value. The function returns the value of a and b added together. Func2 is an example of a function that does not contain any parameters. Func2 is also an example of a procedure. Func2 does not need to return a value, because it only prints "Hello" to the screen, so an expression is not included within the return statement.
Awk# gives developers the ability to declare constants. Constants are useful because they are bound to a value and the value cannot be changed by assignment or by an input statement. The also help with program readability and program reliability.
Example of a constant in Awk#:
BEGIN{
const MAX = 512;
print MAX;
}
This program declares a constant called MAX and sets it to the value 512. The value of MAX is then printed out to screen. If the code tried to change the value of MAX, an error would occur.
Awk# uses Boolean Data Types, perhaps the smallest of all types. Their range of values has only two elements, zero and one. For the convince of the developer, the constant true is predefined as 1 and the constant false is predefined as 0. Awk# uses these numeric expressions as the return values for conditions. This allows numeric expressions to be used as if they were Boolean.
Example of Boolean Data Constants:
BEGIN{
x = 0;
if ( x == true ) print "true";
if ( x == false ) print "false";
}
This program will print false because x is declared and initialized to 0. X is then tested to see if the left value is equal to the right value for both the values of true and false. Because false has the value of 0, false is printed.
Awk# supports the use of arrays. Arrays, like variable types, cannot be declared explicitly. They are initialized when they are used with an index. If an index is used beyond the initialized size of an array, an array is automatically increased to that size. Arrays also begin at index 0.
Here is an example using an array:
BEGIN{
for (i = 0; i <= 5; i = i + 1)
{
ar[i] = i
print i;
}
}
In this example, the array ar is assigned a value for indexes 0 to 5. Each time through the loop, the array expands in size by one memory cell because an index is used beyond its original size.
Arrays also have an interesting function in Awk# in that they can be used as simple structure instance. This is because an array does not have to be constrained to one data type. For example, if you wanted use a shape structure that includes the number of sides, its color, and its size, you could use the following code:
BEGIN{
const sides = 0;
const color = 1;
const size = 2;
shape1[sides] = 4;
shape1[color] = "blue";
shape1[size] = 5.5;
}
In this example, an instance of a shape type structure is formed named shape1.
Awk# only has two kinds of variables and arrays, local and global. Because there are no formal type declarations, excluding constants, in Awk#, variables are declared when they are first used. Local variables are therefore created when they are used within a function or a piece, and can only be used in the function or program piece they are created in. Global variables, although not explicitly declared with types, have to be used within the global declaration area. They take the form of assignments or constants in the first part of the program, before any functions or program pieces are declared. Any global variable used in an assignment or constant declaration in the beginning part of the program can be used anywhere in the program.
Here is a code example of an entire program:
/* Global declarations */
a = 3;
const c = 5;
/* Function definitions */
function proc1()
{
b = 4;
print a;
print b;
return;
}
function proc2()
{
print a;
print b;
return;
}
/* Program Pieces- Activated when the pattern is matched within a line in the file. */
BEGIN
{
proc1();
proc2();
}
In this example, a is declared as a global variable and c is declared as a global constant. The program will start in the BEGIN program piece with its first line, calling proc1. Proc1 will then print out the values of the global variable a and the local variable b. Then proc2 will be called. The global variable a will then be printed, but the next line will cause an error. Because the variable b was never given a value in proc2, it was not created and there fore will cause an error when the function tries to print its value.
Back to Program Diagram
Awk# has the ability of stating conditional statements using an if-else clause. The clause test a condition and if the condition returns 1, then the if statement is evaluated. If the condition returns 0, then the else statement is evaluated. When multiple conditions are needed to satisfy a statement we use a nested ladder of else conditional clauses. At the most basic foundation an if statement allows for sub-branching based upon a conditional boolean expression.
Example of a Conditional if-else statement:
BEGIN{
bool = true;
if( bool )
print "Hello, World.";
else
print "Program failure.";
}
Awk# has the ability of describing a switch-case conditional statement. A switch-case will perform, the case action if the case's expression matches the switch expression. This satisfies the need of having a very long if-else clause instead. If no cases match the expression of the switch statement being tested, an optional default case can be used to deal with such cases.
Example of a Conditional Switch-Case statement:
BEGIN{
selection = 1;
switch(selection)
{
case 1:
print "This is Case 1;
break;
case 0:
print "This is Case 2;
break;
default:
print "EMPTY";
break;
}
}
According to which case that will be chosen the above represents conditional branching in a switch-case statement. The above will print out a specified string if the expression of the switch statement matches the case containing the string.
Awk# has the ability to branch to any line in the program by using labels and the goto statement. Each statement can contain a label as its first portion. The label is separated from the rest of the statement by a colon. A goto statement allows the program to be redirected to a different line, indicated by the label in the goto statement.
Example of Goto and Labels:
BEGIN{
print "Hello World ";
goto Lbl1;
print "This will not be printed";
Lbl1: print "Done";
}
This program will only print "Hello World" and "Done". When the program reaches the line containing the goto statement, it skips to the line containing the label Lbl1, meaning the string "This will not be printed" will not be shown on the screen.
Awk# has three different loops that can be used. Awk# gives developers the ability to repeatedly execute a segment of code using For Loops. The For loop is counter controlled in which a count value is maintained. The code segment is executed from an initial value until a terminal value is reached.
Example of a For Loop in Awk#:
BEGIN {
for(count=0; count<=100; count=count+1)
{
print count;
}
}
This program uses a for loop to print out values of the count. The for loop first initializes a count and sets the value to zero. The code segment is repeated until count reaches above the value 100 while incrementing the count with each pass. The code prints out the values from zero until 100.
Awk# gives developers the ability to repeat a segment of code using a repetition control based on a boolean expression rather then a counter controlled loop.
Example of a While Loop in Awk#:
BEGIN {
while( EndOfFile!=true )
{
print fileValue;
}
}
This program uses a while loop to print file values as long as it does not reach the end of the file.
Awk# gives developers the ability to repeat a segment of code indefinitely using a forever loop. If used in conjunction with the break and continue statements, the forever loop can create a loop where the conditional test occurs in the middle of the loop.
Example of a forever loop in Awk#:
BEGIN {
forever
{
x=x+2;
if(x>50)
{
break;
}
}
}
This program uses a forever loop to increment the value of x by two then print the value. In the middle of the loop the x value is checked, and if above the value fifty it breaks out of the forever loop.
Awk# comes with several statements to help manage the flow of loops. Awk# has the ability to jump to the end of the current repetitive statement. The code between the break call and the end of the repetitive statement is skipped. The condition of the repetitive statement is NOT evaluated.
Example of the Break statement:
/*Program to demonstrate the Break Statement.*/
BEGIN {
I = 0;
while (I < 10)
{
I = I + 1;
if (I > 5) break;
print (I);
}
}/* end begin*/
This program will print "12345". When the program reaches the line containing the break statement in each of the repetitive statements, it exits the current statement.
Awk# has the ability to jump to the end of the current repetitive statement. The code between the continue statement and the end of the repetitive statement is skipped. The condition of the repetitive statement is then checked again.
Example of the continue statement:
/*Program to demonstrate the continue statement.*/
BEGIN{
I = 0;
while (I < 10)
{
I = I + 1;
if ( I < 5) continue;
print (I);
}
}/*end*/
The above program will print "6789." For each loop, type the program will increment a counter variable or each pass. If the value of the counter variable is less than five in each loop, the loop will stop at that point and continue from the beginning of the loop.
Awk # has the ability to exit the current subroutine, and return control to the calling routine with the exit statement. If the exit statement is invoked in the main program routine, exit stops the program.
Example of the Exit statement:
/*Program to demonstrate the Exit Statement.*/
BEGIN{
yes = true
print "Hello this is a normal exit";
if ( yes )
{
print "Bailing out early";
exit;
}
print " continuing to the end";
}
The above program will always print "Bailing out early" and exit the program. The exit statement will cause the program to terminate and never reach the "continuing to the end" output statement.
. . . . . . . . . ( end of section Small Awk) <<Contents | Index>>