0% found this document useful (0 votes)
3 views

assignment01

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

assignment01

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 8

CSCI 235, Programming Languages,

Assignment 1

Rules for Assignments:


• You are expected to read the complete assignment and to complete every
part of it. ’I did not see this part’ will never be a valid excuse for not
completing a part of the assignment.
• Submitted code will be checked for correctness, readability, style, and
layout. We apply high quality standards during grading.
• If you need help, please post your question on Piazza. Questions that do
not contain code can be asked publicly. Questions that contain code must
be posted as private question to all instructors. If you are in doubt, post as
private question, because instructors can always make the question public
later. Don’t mail questions directly to an instructor, because individual
instructors are not always available. Piazza is watched almost full time,
so you will get a quicker answer.
• You must write all submitted code by yourself! Don’t ’cooperate’ with
other students, don’t use AI tools. Such tools do make mistakes, which
we will find. We check code for similarity using automatic tools and also
by visual inspection. See the syllabus for additional rules. You may be
invited for live grading, or for discussion about the quality of your code.
• We use a two-phased grading, as in CSCI 152. Submissions are checked
with an automated tester, and you should receive the results on the next
day. You then have opportunity to update your submission until the final
deadline. The grade for your final submission will your grade for the
assignment.
Since we use an automatic checker, it is possible that small mistakes in
your code have disastrous consequences. For example, the names of your
files can be wrong, the names of your methods may be wrong, and some-
times your IDE may add some non-standard imports into your code. The
purpose of the first deadline is to give you an opportunity to repair such
small but disastrous mistakes. The first deadline is not intended as an
opportunity for procrastination. Since our submission procedure already
gives two opportunities, there will be no further possibility to submit or

1
correct anything after the second deadline, not even for partial credit.
You should always treat the first deadline as if it is the only deadline, and
avoid using the second.

Java Coding Rules


• Use camel case for all your identifiers. Method names must start with
a lower case letter. Class names start with an upper case letter. Local
variables start with a lower case letter. Field names start with a lower
case letter. Package names should be all lower case.

• Use the Oracle Documentation for looking up Java classes.

1 Introduction
In this assignment, you will learn more about how overriding with dynamic
dispatch can be used to implement choices that need to be made at run time.
Dynamic dispatch is a form of runtime polymorphism. You already have seen
compile time polymorphism in C ++ in the form of templates. Templates are
also polymorphic, but the concrete type must be known at compile time. Java
also has a kind of templates, which are called generics.
Using overriding with dynamic dispatch is the preferred approach when
choices need to made at run time, and the possible options are not known
in advance. When it later turns out that another option is needed, one can
create a new subclass and override the required methods for this subclass. If
one would use another choice mechanism, like for example switch or if, one
would have to search for these statements in the code, and add the new option
to all of them.
In this assignment, you will implement a simple, functional language, which
we creatively call SFL. The language uses different types of expressions which
need to be printed and evaluated (computed). In order to decide how a sub-
type of expression is printed/evaluated, we will override the toString( ) and
evaluate( ) methods.
Functional languages are programming languages whose programs are simi-
lar to mathematical expressions. Computation is done by computing the result
of the expression, assuming that the variables in it have certain values. In a
functional language, values of variables can be defined once, but not overwrit-
ten. The languages that you are familiar with are called imperative. In these
languages, computation is based on a state that is changed by commands of
the programming language. Functional languages don’t use state. Computing
the value of an expression is usually called evaluating the expression. In order
to fully appreciate functional programs, one would have to introduce symbolic
computation (computations that work on trees, not only on primitive, CPU dic-
tated types) and higher-order functions (these are functions whose arguments
are functions). The most used functional languages are Scala, OCaml, and
Haskell.

2
2 SFL
SFL uses a single type, unbounded precision integers. The main building block
of SFL programs are expressions, which are recursively defined as follows:
• A variable is an Expression.
• A integer (unbounded) is an Expression.
• If E is an Expression, and op is a unary operator, then op(E) is an
Expression.
• If E1 and E2 are Expression, and op is a binary operator, then op(E1 , E2 )
is an Expression.
• If E1 , . . . , En with n ≥ 0 are Expressions, and op is an operator with
arbitrary arity, then op(E1 , . . . , En ) is an Expression.
• If C, Et , and Ef are Expressions, then If (C, Et , Ef ) is an Expression.
• If str is a String, and E1 , . . . , En with n ≥ 0 are Expressions, then
str(E1 , . . . , En ) is an Expression.
• If str is a String, then Fail( str ) is an Expression.
An SFL-program is a sequence of function definitions. A function definition con-
sists of a String (the name of the function), a parameter list (distinct Strings),
and a body, which is an Expression as defined above. Since there is only one
type, there is no need to specify the type of the parameters in a function def-
inition. Function names can be overloaded by arity, which means that the
same function name can be reused, as long as the parameter lists have different
lengths.
In order to evaluate an Expression, one needs a Program and a Context.
The context remembers the values of local function variables. It is a mapping
from String to BigInteger.
During evaluation, sometimes BigIntegers need to be interpreted as booleans.
In that case, 0 is mapped to false, and all non-zero values are mapped to true.
The rules for evaluating Expressions are as follows:
• When a variable is evaluated, it is looked up in the context. If the variable
does not occur, evaluation fails.
• The evaluation of an integer constant equals the constant itself.
• A unary Expression op(E) is evaluated as follows: First evaluate E,
using the same Program and Context. Call the result i. After that, the
result is determined by the following table:

op result
neg −i
not !i

3
In the last case, i is first converted to a boolean by the rule given above.
In the result, false will converted to 0, and true will be converted to 1,
because evaluation must return a BigInteger. If op does not occur in
the table, evaluation fails.
• A binary Expression op(E1 , E2 ) is evaluated as follows: First E1 and
E2 are evaluated, assume that the results are called i1 and i2 . After that,
the result is determined by the following table:

op result
sub i1 − i2
floordiv i1 /i2 (rounded down)
mod i1 mod i2
eq i1 = i2
ne i1 6= i2
lt i1 < i2
gt i1 > i2
le i1 ≤ i2
ge i1 ≥ i2

In the comparison operators, false will converted to 0, and true will be


converted to 1, because evaluation must return a BigInteger. If op does
not occur in the table, evaluation fails.
Both floordiv and mod fail if i2 = 0.
• An arbitrary arity Expression op(E1 , . . . , En ) is evaluated as follows:
– If op is one of add or mul, then first all Ej (1 ≤ j ≤ n) are evaluated,
assume that the results are called i1 , . . . , in . After that, the result is
determined by the following table:
op result
add i1 + · · · + in
mul i1 . · · · .in
– If op equals and, then we want to return 0 if one of the subExpressions
evaluates to 0, and return 1 otherwise. We want to do this in such a
way, that we stop evaluating as soon as a subExpression evaluates
to 0. This is called short-circuit evaluation. In order to do this, we
evaluate the Ej (1 ≤ j ≤ n) from left to right, until the first Ej eval-
uates to 0. If we reach the end because no Ej evaluated to 0, then
evaluation returns 1.

4
– If op equals or, then we want to return the result of the first Ej
that does not evaluate to 0. In order to do this, we evaluate the
Ej (1 ≤ j ≤ n) from left to right, until we reach the first Ej that
evaluates to a non-zero value.
If we reach the end, because all Ej evaluated to 0, then evaluation
returns 0.
• An Expression of form If (C, Et , Ef ) is evaluated as follows: First C is
evaluated, call the result c. If c is different from zero, then the result of
evaluating If (C, Et , Ef ) will be the result of evaluating Et . Otherwise, it
will be the result of evaluating Ef . If behaves the same as the ternary
operator c ? t1 : t2 in C (or Java).
• An Expression of form str(E1 , . . . , En ) is evaluated as follows: First all
E1 , . . . , En are evaluated in the current Context, call the resulting values
i1 , . . . , in .
– If the program contains a function definition for string str with a
parameter list (S1 , . . . , Sn ) whose length is n, then let Ebody be the
body of this function. Create a new context Cnew that maps each Sj
to ij . After that, the result is obtained by evaluating Ebody in the
new context Cnew .
– If no fitting function definition exists, evaluation fails.
• An Expression of form Fail(str) is ‘evaluated’ by throwing an exception
containing str.

3 Tasks
The task is to implement all subclasses of Expression. All classes must be cre-
ated in package (and corresponding directory) sfl.expression. The file name
must always be equal to the class name. The Oracle documentation for BigIn-
teger can be found here. If a specification below says ‘throws an Exception’
this is always an sfl.program.Exception.
If you want to print the arguments during evaluation, you can call method
show( Program, Context ) defined in Expression. All your implemented
classes can access it, because they are subclasses of Expression.
Class Expression contains dummy .toString( ) and evaluate( Program
prog, Context ctxt ) methods, which throw an Exception when they are
called. Normally, one would make these classes abstract, but then your pro-
gram cannot be compiled when it is unfinished. If you want, you can make the
methods abstract in the end. In order to test your evaluation methods, you
can use sfl.Tester.tester. When you are finished, you should run the tests in
sfl.Tester.main.

1. Create the class IntConst. It must have the following methods:

5
public IntConst( BigInteger value )
// Must store the value.
public IntConst( String val )
// Converts val to a BigInteger and stores it.
public String toString( )
public BigInteger evaluate( Program prog, Context ctxt )
throws Exception
// returns the stored value.

2. Create the class Variable. It must have the following methods:

public Variable(String name)


public String toString( )
// Returns the variable name.
public BigInteger evaluate(Program prog, Context ctxt)
throws Exception
// Looks up the name in ctxt, throws
// an Exception if it is not there.

3. Create the class Unary. It must have the following methods:

public Unary( String op, Expression sub )


public String toString( )
// Returns a string of form op( ... )
public BigInteger evaluate(Program prog, Context ctxt)
throws Exception
// See the explanation above. Must throw an
// Exception if op is not a unary operator.

4. Create the class Binary. It must have the following methods:

public Binary(String op, Expression sub1, Expression sub2)


public String toString( )
// Returns a string of form op( ... , ... )
public BigInteger evaluate(Program prog, Context ctxt )
throws Exception
// See the explanation above. Must throw an
// exception if op is not a binary operator,
// or when dividing by zero.

5. Create the class Nary. It must have the following methods:

public Nary(String op, Expression... sub)


// Construct Nary term with arbitrary number of subterms.
public String toString( )
// The resulting string must have form op( ... , ... )

6
// with commas correctly put between the subExpressions.
// Make sure toString works correctly when there are no,
// or one subExpression.
public BigInteger evaluate(Program prog, Context ctxt)
throws Exception

Make sure that evaluate correctly handles and and or. It must stop
evaluating as soon as it knows the result, see the explanation above. You
can use method asBoolean in Expression to check if a BigInteger is
non-zero.
6. Create the class If. It must have the following methods:

public If(Expression cond, Expression yes, Expression no)


public String toString( )
// Must return If( ..., ..., ... )
public BigInteger evaluate(Program prog, Context ctxt)
throws Exception

First evaluate the condition. If the condition is not zero, return the eval-
uation of the second argument. If it is zero, return the evaluation of the
third argument. In order to check if a BigInteger is non-zero, use method
asBoolean( BigInteger ), defined in Expression.
7. Create class Function. It must have the following methods:

public Function(String funcname, Expression... arguments)


// Constructs a Function with arbitrary number of arguments.
public String toString( ).
// Returns "funcname"( ... ). Make sure that funcname is
// quoted, and commas are put correctly between the
// arguments.
public BigInteger evaluate(Program prog, Context ctxt)
throws Exception

evaluate works as follows:


(a) Check if prog contains a function with the correct arity. If not, throw
an Exception.
(b) Create a new Context.
(c) Evaluate the arguments, and match them to the parameters in the
new Context.
(d) Evaluate the function body using the new Context.
Look at classes Program Functiondef, and Context, before you imple-
ment anything.

7
8. Finally, it is convenient to have a type of Expression that always fails.
Implement class Fail. It must have the following methods:

public Fail(String cause)


public String toString( )
// Must return (not throw!) a string of form
// "fail( ... )".
public BigInteger evaluate(Program prog, Context ctxt)
throws Exception
// Always throws the Exception, never returns.

4 Examples
Some examples can be found in sfl.Tester.main. You should add more exam-
ples by yourself. This will help you understanding functional programming.

5 Submission Instructions
Locate the project folder for the assignment on your computer, and zip up
the entire src folder which contains all of your .java files, without changing
any of its contents or directory structure – this should reduce the chances of
accidentally removing a needed file or making unwanted changes. Submit this
zip file to Moodle in the proper submission box before the deadline. Note that
the auto-grader will search for, and extract the .java files in the expression
package that you implemented yourself from src, and recreate the exact original
package structure before testing. Thus, it is critical that you don’t modify the
Java classes and packages that have been provided.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy