Graphfruit Documentation.docx

advertisement
UNIVERSITY OF NORTH FLORIDA
Graphfruit
A Graphing Language for the Modern Age
Jamie Gordon & Emroy Wingard
11/19/2013
Graphfruit
Introduction
The Graphfruit language is designed to use the flexibility of a programming language to design and
implement graphs. The programming language uses design ideas from C-like languages, but excludes
the bracketing syntax to make code more readable.
Procedural Language
Graphfruit is a procedural language. Procedures can be programmatically created to manipulate
numbers and equations for graphing later on. In this case, Graphfruit is a high-level abstraction of the
graphing system.
Design Goals
Graphfruit was designed to be a high-level language that would allow programmers to easily make
graphs. It was also designed so that code could be easily moved from program to program and be
reused for different graphing situations. A list of specific goals follow.







High-level of abstraction allowing programmers to ignore such factors as data calculation
Ability to graph more than one equation on a single set of axes
Ability to program piecewise functions
Accurate graphs
Include basic operations for equation construction
Allow programmers to implement any operations that are not included in the specification
procedurally
Remove hindrances to readability found in other C-derivatives, like brackets and semicolons
instead using newlines and the keyword end.
Graphfruit Language Design
Data Types
There are two data types.
1. Numbers – Numbers in Graphfruit are just that, numerical values. Graphfruit does not
distinguish between integers and floating point numbers. (In actuality, they are both treated as
doubles in the backend). The reason for this is that once the graphing is done, 2000 points of
data are calculated to graph the function. These will most likely be floating point numbers
themselves.
2. Equations – In Graphfruit equations are what will be graphed at the end of the program. They
are delimited with accents, ``. Equations must be expressed in terms of x. Equations are
basically Strings, but with a few other behaviors. For example, all the operations (with the
exception of modulus) can be applied to equations. What this does, in effect, is combine
equations together using the operation. For example,
`x ^ 3 – x ^ 2` + `x * 3`
Will yield:
`x ^ 3 – x ^ 2 + x * 3`
`3 * x + 4` / `x ^ 2`
Will yield:
`( 3 * x + 4 ) / ( x ^ 2 )`
Arrays
You can also use arrays with Graphfruit. You can make arrays of numbers or equations. Graphfruit does
not support returning arrays or graphing arrays, the latter of which does not make much sense to do.
Data Type Use
The way to declare variables or equations in Graphfruit is to use the data type specifier in front of the
variable id. This is also how you declare you functions using a type specifier. There are no void
functions in Graphfruit. Because the whole point of the language is to output graphs, using functions
that do not return a value makes no sense. All graphing is done in main().
Another note, variables must be declared at the beginning of a function or control statement body,
before all other statements are given. Global variables are allowed.
Variable Declaration
num factor
equation eq
Function Declaration
num factorial(num
factor)
equation sine()
Array Declaration
num factor[3]
equation eq[5]
Comments
Comments are specified using #. This symbol comments out the whole line.
Operators
Below is a list of all operators that can be used on the data types. If an operator is performed on a
number and equation together it defaults to the equation behavior. An operation cannot be performed
on a whole array.
Operator
Number
Equation
+
*
/
^
Adds numbers
Subtracts numbers
Multiplies numbers
Divides numbers
Raises number to
power
Modulus for number
Concatenates equations or numbers using addition
Concatenates using subtraction
Concatenates using multiplication, with parentheses
Concatenates using division, with parentheses
Concatenates using exponentiation, with parentheses
mod
Error
Functions
As stated previously, all methods (excluding main) return a value. Main is special and will be discussed
in the next section. In addition, there are no curly brackets used. Statements are ended with newlines
rather than semicolons, as shown below.
equation stuff(num number)
equation eq = `x`
if (number > 0)
eq = eq ^ `2`
else
eq = eq ^ `-2`
end
return eq
end
Specifics of Main
In Graphfruit, the main declaration holds a very special significance. First of all it is the only void
function and is declared thusly:
def main()
…
end
However, this is not the only special thing about main. This is where you specify the equations that you
wish to graph, using the graph keyword rather than return:
def main()
…
graph `x` from x = 0 to 10, y = 10 to 10
end
The from keyword specifies the values of x to use in the graph and how tall the graph should be. The
entire from syntax can be disregarded, in which case -10 to 10 is assumed for both x and y. You can
also choose to only specify x or y. Multiple graph statements can be used. If the ranges overlap, you
will get overlapping graphs. If they do not overlap, you will get a piecewise graph, like below. This is
the result of the example in Appendix D.
The size of the graph is determined by the Gaph Frame. The graph frame chooses the most extreme
values provided to graph the function. For example, if one said:
Graph `x` from x = -7 to 5, y= -8 to 4
Graph `x^2` from x=-10 to 0, y = -5 to 10
The x-axis would range from -10 to 5 and the y-axis would range from -8 to 10.
Details about Compilation and Execution
A helpful diagram is included (Appendix A) to show the full process.
Lexical Analysis
A text file is fed into the compiler. The compiler sends the file to the lexical analyzer. The lexical
analyzer splits the file into useful tokens and labels the tokens for use in the compiler.
Compilation
The compiler then uses these tokens to parse the file. If the file passes this syntactic analysis—based on
the grammar in Appendix B—the file moves on to semantic analysis. In semantic analysis, it is made
sure that the correct expressions are used at the correct time, such as checking that data types are used
in a legal manner.
Intermediate Code Generation
Once it passes semantic analysis, intermediate code generation can take place. Intermediate code
generation creates a .gph file. The file name is simply the original file name appended with .gph. This
means that the GraphfruitCompiler.java compiles the code, and the .gph code can be run multiple times
without the need for recompiling the code.
Execution
Code is run using the Graphfruit execution environment, using the Graphfruit.java file. This program
interprets and runs the quadruples. This will generate a number of equations, with x and y ranges.
Equation Interpretation
These equations are sent to the GraphFrame, which then takes over. The GraphFrame sends the String
equations to the EquationLexicalAnalyzer, which generates String tokens for the EquationParser. The
EquationParser interprets the tokens to create sets of x-points and y-points. The GraphFrame then
takes these sets of points and graphs them.
Conclusion
In summary, code is programmed into a text file. This text file is then run using java
GraphfruitCompiler textfile. This produces a file called textfile.gph. This graph file is
run using java Graphfruit textfile.gph. This produces a set of strings, which is also
tokenized and then interpreted. A graph is then created.
Troubleshooting
It may also be necessary to compile the source first. Run javac *.java in the source directory.
Then, to run the compiler type java compiler.GraphfruitCompiler textfile and java
execution.Graphfruit textfile.gph. This may fix any errors you may have. You need to be
able to run java swing resources.
Criteria for Language
Efficiency
Graphfruit execution is interesting. Code is compiled into an intermediate language. This means that
code should be faster than typical execution. However, when the quadruples are executed, the code
produces equations, which are then interpreted. Theoretically, the equations that are produced could
also be outputted as a text file (so they wouldn’t have to be reproduced on each execution). However, it
was decided that for future work (adding in user interactions through console input), this should not be
included. The language is also written in Java, so it is dependent on the performance of the JVM.
Simplicity
Readability
I believe that the code is very simple to read. With the exclusion of things like brackets, code is more
easily understood. The graph keyword syntax is very naturally read. Having the graph expressions on
the bottom of the program makes a lot of sense, given that it will be the final result of your program.
Writability
Someone familiar with C-like syntax should be able to easily write code, and the addition of the graph
reserved word should be easy to pick up because its format is written very naturally.
Orthogonality
As there are only two data types, orthogonality is well preserved. All operations (except modulus) can
be performed on both data types. While none can be performed on arrays themselves, arrays typically
cannot have operations performed on them in C-like languages.
Portability
This code can be run on any environment Java can be run on, provided swing can be run with it. It has
no real meaning in a console environment. The user will be informed of this fact if execution is
attempted in a console environment.
Future Work
Because of the time restraints, not all ideas could be executed. Some of these ideas follow.
More operations
Currently, the language only supports addition, subtraction, multiplication, division, modulus, and
exponents. Graphing supports all the same operators, excluding modulus. Many other binary
operations could be relatively easily added to the language specification, given time. However, at the
moment, only binary operations are currently supported in the grammar.
Adding unary operations, like trigonometric functions (sine, cosine, etc.) or logarithms, cannot be as
easily inserted into the grammar. While these would be useful, especially in the equation parser, time
concerns were an issue. The good news is that many of these operations can be implemented using the
current grammar programmatically, with a little research. This document shows an example of how to
approximate sine using a Taylor series (Appendix D).
Interactivity
Program interactivity was shelved for Graphfruit. It would be nice to take in user input as well as
programs. Another version of interactivity might be to allow users to click on parts of the graph and get
the x and y coordinates.
Graph Display
Graphing has many features even now, but there are other features that could be added. For example,
adding numbers to the number lines might be useful to the user.
Another useful programming feature could be to allow the programmer to specify coloration of the axis
and the lines. The specification could be updated to add the ability to program multiple axes in different
panels in a single frame, or even have multiple windows open.
Conclusion
There are many options that could have been included into the Graphfruit specification, but the
important features had to be chosen so that the project could be completed in the allotted time.
Appendix A - Compilation and Execution
Lexical Analysis
Tokens
Parsing
Semantic Analysis
Outputs
Filename.gph
GraphfruitCompiler.java
Code Generation
Quadruples
Graphfruit.java
Execution
Equations
Graph
GraphFrame.java
Graphing
Equations
Points
EquationParser.java
Equation
Parser
Tokens
Equation
Lexical
Analysis
EquationLexicalAnalyzer.java
Appendix B - Graphfruit Grammar
Prgm -> DeclarList MainDeclar | MainDeclar
DeclarList -> Declar DeclarList'
DeclarList' -> Declar DeclarList' | @
Declar -> DataType ID Declar'
Declar' -> VarDeclar' AssignmentStmt newline | FunDeclar
FunDeclar -> ( ParamList ) Body end newline
DataType -> num | equation
ParamList -> Param ParamList' | @
ParamList' -> , Param ParamList' | @
Param -> DataType ID Param'
Param' -> [ ] | @
VarDeclar -> DataType ID VarDeclar' AssignmentStmt newline
VarDeclar' -> [ NUM ] | @
AssignmentStmt -> = Expression | @
Body -> newline LocalDeclarList StmtList
LocalDeclarList -> LocalDeclarList'
LocalDeclarList' -> VarDeclar LocalDeclarList' | @
StmtList -> StmtList'
StmtList' -> Stmt StmtList' | @
Stmt -> ExpressionStmt | SelectionStmt | IterationStmt | ReturnStmt
ExpressionStmt -> Expression newline | ;
SelectionStmt -> if ( Expression ) Body SelectionStmt'
SelectionStmt' -> else Body end newline | end newline
IterationStmt -> while ( Expression ) Body end
ReturnStmt -> return Expression newline
Expression -> ID Expression' | Factor' Expression'''
Expression' -> Var' Expression'' | ( Args ) Expression'''
Expression'' -> = Expression | Expression'''
Expression''' -> ExponentialExpression' MultiplicativeExpression'
AdditiveExpression' SimpleExpression'
Var' -> [ Expression ] | @
SimpleExpression' -> Relop AdditiveExpression | @
Relop -> <= | < | > | >= | == | !=
AdditiveExpression -> MultiplicativeExpression AdditiveExpression'
AdditiveExpression' -> Addop MultiplicativeExpression
AdditiveExpression' | @
Addop -> + | MultiplicativeExpression -> ExponentialExpression
MultiplicativeExpression'
MultiplicativeExpression' -> Mulop ExponentialExpression
MultiplicativeExpression' | @
Mulop -> * | / | mod
ExponentialExpression -> Factor ExponentialExpression'
ExponentialExpression' -> Exop Factor ExponentialExpression' | @
Exop -> ^
Factor -> ID IndexCall | Factor'
Factor' -> ( Expression ) | NUM | EQ
IndexCall -> Var' | ( Args )
Args -> ArgList | @
ArgList -> Expression ArgList'
ArgList' -> , Expression ArgList' | @
MainDeclar -> def main ( ) Body GraphList end
GraphList -> Graph GraphList'
GraphList' -> newline Graph GraphList' | @
Graph -> graph Expression GraphOpts
GraphOpts -> from Opts | @
Opts -> XRange YOpts | YRange XOpts
XRange -> x = Range
YRange -> y = Range
XOpts -> , XRange | @
YOpts -> , YRange | @
Range -> Expression to Expression
Appendix C - Typical Executable (.gph)
File
Index Operator Operand1 Operand2
Result
0
ALLOC
NUM
~
global
1
ALLOC
NUM
3
snuff
2
ALLOC EQUATION
~
xl
3
ADD
`x`
1
t0
4
ASGN
t0
~
xl
5
FUNC
getNum
NUM
1
6
PARAM
NUM
~
funNum
7
BLOCK
~
~
~
8
ASGN
2
~ snuff[2]
9
MULT
funNum
3
t1
10
RETURN
~
~
t1
11
END
~
~
~
12
FUNC
stuff EQUATION
1
13
PARAM
NUM
~
number
14
BLOCK
~
~
~
15
ALLOC EQUATION
~
eq
16
ASGN
`x`
~
eq
17
COMP
number
0
t2
18
BRGT
t2
~
20
19
BR
~
~
25
20
BLOCK
~
~
~
21
EXP
eq
`2`
t3
22
ASGN
t3
~
eq
23
END
~
~
~
24
BR
~
~
29
25
BLOCK
~
~
~
26
EXP
eq
`-2`
t4
27
ASGN
t4
~
eq
28
END
~
~
~
29
RETURN
~
~
eq
30
END
~
~
~
31
FUNC factorial
NUM
1
32
PARAM
NUM
~
factor
33
BLOCK
~
~
~
34
ALLOC
NUM
~
index
35
ASGN
factor
~
index
36
ALLOC
NUM
~ product
37
ASGN
1
~ product
38
COMP
index
0
t5
39
BRGT
t5
~
41
40
BR
~
~
48
41
BLOCK
~
~
~
42
MULT product
index
t6
43
ASGN
t6
~ product
44
SUB
index
1
t7
45
ASGN
t7
~
index
46
END
~
~
~
47
BR
~
~
38
48
RETURN
~
~ product
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
END
~
~
~
FUNC
sine EQUATION
0
BLOCK
~
~
~
ALLOC
NUM
~
index
ASGN
1
~
index
ALLOC EQUATION
~
eq
ASGN
`x`
~
eq
COMP
index
15
t8
BRLT
t8
~
59
BR
~
~
76
BLOCK
~
~
~
EXP
-1
index
t9
MULT
2
index
t10
ADD
t10
1
t11
EXP
`x`
t11
t12
MULT
t9
t12
t13
CALL factorial
1
t14
MULT
2
index
t15
ADD
t15
1
t16
ARG
t16 factorial
factor
DIV
t13
t14
t17
ADD
eq
t17
t18
ASGN
t18
~
eq
ADD
index
1
t19
ASGN
t19
~
index
END
~
~
~
BR
~
~
56
RETURN
~
~
eq
END
~
~
~
FUNC
main
void
0
BLOCK
~
~
~
ALLOC EQUATION
~
funEq
CALL
getNum
1
t20
ARG
2
getNum
funNum
ASGN
t20
~ snuff[1]
CALL
stuff
1
t21
CALL
getNum
1
t22
ARG
2
getNum
funNum
ARG
t22
stuff
number
ADD
t21
`x`
t23
ADD
t21 snuff[1]
t24
ASGN
t24
~
funEq
CALL
sine
0
t25
XOPT
-5
-1
~
YOPT
-10
10
~
GRAPH
~
~
t25
XOPT
-1
5
~
YOPT
-10
10
~
GRAPH
~
~
funEq
Appendix D – Sample Program
num arr[5]
num getNum(num funNum)
return funNum * 3
end
equation stuff(num number)
equation eq = `x`
if (number > 0)
eq = eq ^ `2`
else
eq = eq ^ `-2`
end
return eq
end
num factorial(num factor)
num index = factor
num product = 1
while (index > 0)
product = product * index
index = index - 1
end
return product
end
equation sine()
num index = 0
equation eq = `x`
# Taylor series
while (index < 4)
eq = eq + (-1) ^ index * `x` ^ (2 * index + 1) /
factorial(2 * index + 1)
index = index + 1
end
return eq
end
def main()
equation funEq = stuff(getNum(2)) + `x`
arr[2] = getNum(3)
funEq = funEq + arr[2]
graph sine() from x = -5 to -1, y = -10 to 10
graph funEq from x = -1 to 5, y = -5 to 5
end
Download