Giter Site home page Giter Site logo

src's Introduction

joshsvoss
shanam



=============================
=      File description     =
=============================

************************

PACKAGE: oop.ex6.main :  This package contains the main method and its class, Sjavac.java. It also
contains the parser and all of the exceptions that are thrown in the parser and not in the 
deeper methods that it calls.  It also contains the SymbolTableList class which wraps a Vector
of HashMaps for storing the variables at different scopes.  

DoubleDeclarationInScopeException.java - This Exception is to be thrown when two variable of the same 
name are declared in the same scope.

GlobalClosingBracketException.java - This exception is thrown when the parser encounters a closing bracket 
in the global scope.

GlobalIfWhileException.java - This exception is thrown when the parser encounters an if or while block in 
the global scope. 

GlobalMethodCallException.java - This exception is thrown when a method is called in the global scope.

GlobalReturnException.java - This exception is thrown when a return statement is encountered 
in the global scope.

IncorrectVariableSyntaxException - This exception is thrown when a variable is declared with 
incorrect syntax.  

MissingMethodReturnException.java -  This exception is thrown when a method is missing its return 
statement.  

NestedMethodDeclarationException.java - This exception is thrown when a method is declared inside another.  

Parser.java - This class handles reading in the Sjava file and parsing through it.

Sjavac.java - This class is the driver class of the Sjava code legality verifier. It invokes the 
parser of Parser.java, and also catches all of the various SJavacExceptions, prints the correct
number (0, 1, 2) to std out, and prints the exception's specific error message + line number to std err.

SJavacException.java - This is the parent exception for all exceptions of Sjava syntax nature.  All 
exceptions that are thrown because of a problem with the Sjava program specified in the cmd line argument
extend this exception.

SymbolTableList.java - This is the class for the  SybolTableList, a data structure that holds our variables.
It wraps a Vector of HashMaps of type <String, Type>.  All of this classes functionality was originally
just in Parser.java, but we decided to delegate it to it's own separate class for modularity and
expandibility: to make it easier to use a new underlying data structure if we so choose, and to be 
able to use this data structure for other purposes in the future.  

UndeclaredAssignmentException.java - This exception is thrown when the sjava program attempts to assign 
a value to a variable that hasn't been declared.  

UnmatchedSyntaxException.java - This exception is thrown when the line parsed doesn't 
match any of our regex formulas, and therefore must be incorrect.

WrongMethodNameException.java - This exception is thrown when a method is called with a name that 
doesn't exist.  

*****************************

PACKAGE: oop.ex6.scopes: This package contains the files that relate to checking the syntax
of code blocks and scopes: such as if statements, while loops and methods. It also contains the e
exceptions that they throw.  

IfWhile.java - This class performs static syntax validation checks on an if or while statement in 
Sjava document.  

IncorrectNumArgsException.java - This exception is thrown when a method is called with the incorrect number 
of args.  

InvalidParameterSyntaxException.java - This exception is thrown when the parameter declaration of a 
method is invalid.  

Method.java - This class implements the Method object, which houses all details of the method declared.

MethodNamespaceCollision.java - This exception is thrown when two methods have the same name.  

ParameterNotInitializedException - This exception is thrown when a method is called with passing arguments 
that haven't yet been initialized.


*****************************

PACKAGE: oop.ex6.types: This package contains the different Type objects and their superclass
Type.java and  the exceptions that they throw. 

AssignmentFromUninitializedVarException.java - This exception is thrown when one variable was assigned the 
value of another which wasn't initialized. 

Boolean.java - This is the class for the Boolean Type variable.

Char.java - This is the class for the Char Type variable.

Double.java - This is the class for the Double Type variable.

FinalVariableException.java - This exception is thrown when a final variable is reassigned.

Int.java - This is the class for the Int Type variable.

InvalidTypeException.java - This exception is thrown when an illegal type is declared.

InvalidValueException.java - This exception is thrown when an illegal value is assigned to a variable.

StringType.java - This class implements the object StringType.  This class is used to create object that 
represent variable of the type String. The name "StringType" was used to avoid namespace collision with the 
Java class String.

Type.java - The parent class for all the type objects (Int, Char, etc).

TypeFactory.java - This class has the job of received a string that defines what type to create, and trying 
to create an instance of the corresponding type.  If the string passed in does not match any of our 
patterns, we throw an exception.  

UninitializedFinalVariableException.java - This exception is thrown when a final variable is declared 
without initialization.

******************************


=============================
=          Design           =
=============================

We chose to divide the program into 3 different packages based on their different purposes.  The main 
package contains the driver class "Sjavac" and it's main method as well as the parser (and of course 
all of the exceptions that are thrown by these classes, as will be the case in each package), and the data
structure in which we stored the variables we created, SymbolTableList.
We decided to create objects for each type of variable, int, String, char etc, since in order 
to check the syntax of Sjava, we need the variables to persist so we can keep track of who they 
are (name) and what their value is, as well as if they've been initialized and are final etc.  
All the different variable objects extend the Type superclass, both to adhere to the DRY principle
by centralizing all common code in one place, and to be able to refer to all of the different types
by type Type, like we do when we create the symbol table HashMaps of type <String, Type> (Polymorphism).
 
 We used the factory paradigm for creating instances of the different types, so it can 
 look a the string it's passed and attempt to create a object of the correct type.  This also allows
 us to catch the situation where the string specifies a type that we don't recognize, such as 
 "superBoolean b = true;", in which case we throw a specific appropriate exception.  
 
 The scopes package deals with parts of the code that are a scope of their own, namely: if statements, 
 while loops, and methods.  Out of these, only the methods need to actually be instantiated and 
 kept in a data structure so we can keep track of them.  Therefore, although we initially started with
 a common parent class Scope.java, as we progressed and realized that the ifWhile checks
 can be performed statically and there was no need to create an ifWhile object, we thinned out 
 the ifWhile.java class and got rid of all of it's unnecessary getters and setters, made it static
 and had the checks be performed inside checkLogic() instead of the constructor.  We then got rid 
 of the Scope parent class, since all of it's functionality was only used by the Method class.  
 
 To check the general syntax of each line of code from the source file, we used regular expressions, 
 Java's Pattern and Matcher classes.   Creating one regex per legal type of line (i.e. variable declaration,
  method declaration, variable assignment, etc.). All of these regexes were placed in our parser class, 
  allowing us to weed out any general syntax errors with the first read through. We also used a couple of 
  other regexes, for example to ensure that legal values are assigned to the variables, as well as to 
  split a list of paramaters, variables, or conditions.
 
 Number of passes through file:
 We concluded that two passes over the text of the file was the best way to organize the parsing: 
 first to add all global variables to our symbol table list and add all Method objects
 to our Method list (which is a hashmap), and THEN to parse through all of the code inside the method 
 scope (and below).  We need to do this since anywhere inside one of the methods, 
 they can refer to either a 1) global variable or 2) a declared method.  So we need to know what 
 all of these are before we enter into the text INSIDE the methods.  Since some of these variable
 and method declarations may come physically AFTER a method's body, but LOGICALLY come BEFORE, 
 we ignore the method bodies on our first "Global" iteration.  While this isn't the fastest approach,
 we chose to sacrifice a negligible cost in time for an increase in both the speed of coding and the level
 of readability.  
 Now the downside of this approach is two times reading the file from disk.  In our case, the code
 files that we deal with are small enough that this "extra" call to disk would be completely negligable.
 But if this syntax verifier were to be used with a LARGE suite of software, then it might be 
 worth it to get rid of the second read from disk by: Reading in all of the code file once, and
 saving it to memory in an array of Strings.  This way, yes you would have to access that string array
 twice just like the file, but it will be stored in RAM not the disk, which is a much 
 less expensive call.  
 
 

=============================
=  Implementation details   =
=============================

See above.

=============================
=    Answers to questions   =
=============================
********************
ADDING OTHER VARIABLES:
Adding a new variable type to the spec of Sjava and therefore to our syntax verifier would fit
well with our design.  We already have a separate class for each type of variable, so we would just create
a new class in the types package, for example called "Float.java". It would have a constructor and implement
the other methods that Type demands: doesValueMatchType() and doesTargetTypeMatchSource().  The
first would make sure that the value assigned to the variable is of the right syntax, for example with a 
float "7" or "7.0" or "7.0F" etc.
In addition, we'd have to change the regexes in the parser that deal with variable declarations
(as well as those in the parameter list of a method), by adding the option of having the type substring (eg.
"float") at the beginning of the variable declaration line.  

*********************
ADDING ARRAYS TO SJAVA:

Syntax issues for arrays:
1) Size of the array in declaration must be > 0
2) Size variable has to be an int
3) The type of the array must be resolved to one or our Type subclasses, since objects don't exist in
SJava
4) The type must be the same on both sides of the assignment statement: String[] arr = int[x]; is illegal.
5) Statements like "arrayName[i]" would be legal only if arrayName pointed to an array type, and not
one of the other Type subclasses.  

We would add a class Array.java to the types package, and it would extend the Type class.  
This way we can keep track of a variable that references an array just like the other types 
in out SymbolTableList.  We need to keep track of declared arrays, because if a reference to an
array such as "arr[i]" or "arr.length" is referring to an array that hasn't been declared, that is -
illegal.  
The inherited abstract method "doesValueMatchType" would be implemented to throw an exception
if the assigned type of the array didn't match the declared type of the array, as well as 
ensuring that it is indeed assigned the value of an array. 
The inherited abstract method "doesTargetTypeMatchSource" would do the same checking but for 
assignments to declared array variables, not the "array literal" (if you will) of "new <type>[<size>];".

In other areas the Array type would be much like the other types: it would have an isFinal
field and the checking that comes with it when assigning a new value (if isFinal, and wasInitialized, 
yet we're trying to assign a new value, throw exception).  

The other class that would have to be modified, (besides the addition of Array.java to the types 
package) would be Parser.java in the main package.  We would modify the parsing loop readCode()
by adding another else if statement that would be entered in the case our new array-matching regex
would match with the current line being read.  Inside this else if code block, an object of Array type 
would be constructed and placed into the correct level in the SymbolTableList just like any other variable.  
After creation, a static method called "checkDeclarationSyntax" belonging to the Array class
could be called to throw an exception in the case of a violation.  Alternatively, the regex
match that decides whether to enter the if else block would also be checking the syntax, 
making this uneccessary.  Any reference to this array variable would cause a lookup to be performed in the 
SymbolTableList using its search() method just like a variable of any other type.  





**********************
ADDING SWITCH STATEMENT:

In order to support the switch statement feature, we would implement a new class in the scopes package
called switch. Like the ifWhile class, it would not have a name, however, closer in functionality to the
method class, it would keep track of the condition passed through the switch. We can keep track of this by 
creating a field in the switch class that keeps track of the condition variable type. This is necessary to 
ensure that the cases following, match the type of the condition. It will thus also need a method to check 
the case condition similar to the checkParamLogic() method of the Method class, using the 
doesValueMatchType() method of the Type class.

Other fields it would need are a declaration depth variable to keep track of the opening and 
closing of the switch statement, as well as a boolean field keeping track of whether or not we are under a 
switch case/default, say "inCase". This would be used to determine if the lines following the switch are 
legal. The associated exception classes would also be implemented both in the scopes class and the main 
class.

In our parser class, we would have to add regexes to account for all lines associated with the switch 
statement, for example, "switch(..){", "case..:", default:", etc. with capture groups to allow for 
extraction of conditions. Additionally, we would implement a stack data structure in the parser, to keep
track of open switch statements, and allow us to easily call the current switch statement's methods to check
conditions and such.

Like with the other features supported by SJava, would add an else if block in our readCode() method to 
account for the opening of the switch statement, as well as the other switch block lines. Upon entrance to 
the if else block for the opening of the switch statement, during the second reading, a new switch object 
would be created with its condition type and pushed into the switch stack, the readCode() method would then 
continue. The "inCase" field of each switch statement would remain false until the regex for a case is found 
in an if else block of the readCode() method, at which point it would be switched to true until a break or 
closing curly bracket line are found. Any none opening case lines found while a switch statement is open, 
but the inCase is false, will result in an error. Furthermore, if a case line is found and the switch stack
peaks null, an exception is thrown.

Upon entering the if else block for cases, using the regex capture group, the case condition is 
extracted and checked against the condition type for the peaked switch statement from the stack. If the
condition type is illegal an exception is thrown.

When a scope close match is found the switch stack is peaked and if it is not null and the peaked switch's 
declaration depth is the same as this.depth we pop it from the stack. Like with the case line, if one of the 
other lines associated with a switch block is called when the switch stack is empty, a exception is thrown. 



src's People

Contributors

joshsvoss avatar shana-m avatar

Watchers

James Cloos avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.