summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGustav Sörnäs <gustav@sornas.net>2020-03-22 02:11:32 +0100
committerGustav Sörnäs <gustav@sornas.net>2020-03-22 02:11:32 +0100
commit524294019eb859a2e9ad07ffb1cf5f0574db6024 (patch)
treed5853f7870959faa84bf23e24d813fcda73ca4d5
downloadtdde24-524294019eb859a2e9ad07ffb1cf5f0574db6024.tar.gz
add kod labb6
-rw-r--r--l6/calc.py187
-rw-r--r--l6/kod.py133
2 files changed, 320 insertions, 0 deletions
diff --git a/l6/calc.py b/l6/calc.py
new file mode 100644
index 0000000..ea4d2b3
--- /dev/null
+++ b/l6/calc.py
@@ -0,0 +1,187 @@
+# ----------------------------------------------------------------------------
+# Grammar for the Calc language
+# ----------------------------------------------------------------------------
+
+"""
+
+PROGRAM ::= '[' 'calc' ',' STATEMENTS ']'
+
+STATEMENTS ::= STATEMENT
+ | STATEMENT ',' STATEMENTS
+
+STATEMENT ::= ASSIGNMENT
+ | REPETITION
+ | SELECTION
+ | INPUT
+ | OUTPUT
+
+ASSIGNMENT ::= '[' 'set' ',' VARIABLE ',' EXPRESSION ']'
+
+REPETITION ::= '[' 'while' ',' CONDITION ',' STATEMENTS ']'
+
+SELECTION ::= '[' 'if' ',' CONDITION ',' STATEMENT ']'
+ | '[' 'if' ',' CONDITION ',' STATEMENT ',' STATEMENT ']'
+
+INPUT ::= '[' 'read' ',' VARIABLE ']'
+
+OUTPUT ::= '[' 'print' ',' VARIABLE ']'
+
+EXPRESSION ::= CONSTANT
+ | VARIABLE
+ | BINARYEXPR
+
+BINARYEXPR ::= '[' EXPRESSION ',' BINARYOPER ',' EXPRESSION ']'
+
+CONDITION ::= '[' EXPRESSION ',' CONDOPER ',' EXPRESSION ']'
+
+BINARYOPER ::= '+' | '-' | '*' | '/'
+
+CONDOPER ::= '<' | '>' | '='
+
+VARIABEL ::= a Python string
+
+KONSTANT ::= a Python number
+
+"""
+
+# ----------------------------------------------------------------------------
+# Primitive functions for the Calc language constructs
+# ----------------------------------------------------------------------------
+
+# ----- PROGRAM -----
+
+def isprogram(p):
+ return isinstance(p, list) and len(p) > 1 and p[0] == 'calc'
+
+def program_statements(p):
+ return p[1:]
+
+# ----- STATEMENTS -----
+
+def isstatements(p):
+ isstmnt = lambda s: isassignment(s) or isrepetition(s) or isselection(s) \
+ or isoutput(s) or isinput(s)
+ return isinstance(p, list) and p and all(map(isstmnt, p))
+
+def first_statement(p):
+ return p[0]
+
+def rest_statements(p):
+ return p[1:]
+
+def empty_statements(p):
+ return not p
+
+# ----- STATEMENT -----
+
+# No functions for statements in general. Instead, see the differenct
+# types of statements: assignments, repetitions, selections, input
+# and output.
+
+# ----- ASSIGNMENT -----
+
+def isassignment(p):
+ return isinstance(p, list) and len(p) == 3 and p[0] == 'set'
+
+def assignment_variable(p):
+ return p[1]
+
+def assignment_expression(p):
+ return p[2]
+
+# ----- REPETITION -----
+
+def isrepetition(p):
+ return isinstance(p, list) and len(p) > 2 and p[0] == 'while'
+
+def repetition_condition(p):
+ return p[1]
+
+def repetition_statements(p):
+ return p[2:]
+
+# ----- SELECTION -----
+
+def isselection(p):
+ return isinstance(p, list) and (3 <= len(p) <= 4) and p[0] == 'if'
+
+def selection_condition(p):
+ return p[1]
+
+def selection_true(p):
+ return p[2]
+
+def hasfalse(p):
+ return len(p) == 4
+
+def selection_false(p):
+ return p[3]
+
+# ----- INPUT -----
+
+def isinput(p):
+ return isinstance(p, list) and len(p) == 2 and p[0] == 'read'
+
+def input_variable(p):
+ return p[1]
+
+# ----- OUTPUT -----
+
+def isoutput(p):
+ return isinstance(p, list) and len(p) == 2 and p[0] == 'print'
+
+def output_variable(p):
+ return p[1]
+
+# ----- EXPRESSION -----
+
+# No functions for expressions in general. Instead, see the differenct
+# types of expressions: constants, variables and binary expressions.
+
+# ----- BINARYEXPR -----
+
+def isbinary(p):
+ return isinstance(p, list) and len(p) == 3 and isbinaryoper(p[1])
+
+def binary_operator(p):
+ return p[1]
+
+def binary_left(p):
+ return p[0]
+
+def binary_right(p):
+ return p[2]
+
+# ----- CONDITION -----
+
+def iscondition(p):
+ return isinstance(p, list) and len(p) == 3 and iscondoper(p[1])
+
+def condition_operator(p):
+ return p[1]
+
+def condition_left(p):
+ return p[0]
+
+def condition_right(p):
+ return p[2]
+
+# ----- BINARYOPER -----
+
+def isbinaryoper(p):
+ return p in ['+', '-', '*', '/']
+
+# ----- CONDOPER -----
+
+def iscondoper(p):
+ return p in ['<', '>', '=']
+
+# ----- VARIABLE -----
+
+def isvariable(p):
+ return isinstance(p, str) and p != ""
+
+# ----- CONSTANT -----
+
+def isconstant(p):
+ return isinstance(p, int) or isinstance(p, float)
diff --git a/l6/kod.py b/l6/kod.py
new file mode 100644
index 0000000..060dc21
--- /dev/null
+++ b/l6/kod.py
@@ -0,0 +1,133 @@
+import sys
+
+import calc
+
+def debug(tag, msg):
+ #print("[{}] {}".format(tag, msg))
+ pass
+
+def eval_binary(frame, statement):
+ debug("BINARY", statement)
+ op = calc.condition_operator(statement)
+ if op == "+":
+ return eval_expression(frame, calc.condition_left(statement)) \
+ + eval_expression(frame, calc.condition_right(statement))
+ elif op == "-":
+ return eval_expression(frame, calc.condition_left(statement)) \
+ - eval_expression(frame, calc.condition_right(statement))
+ elif op == "*":
+ return eval_expression(frame, calc.condition_left(statement)) \
+ * eval_expression(frame, calc.condition_right(statement))
+ elif op == "/":
+ return eval_expression(frame, calc.condition_left(statement)) \
+ / eval_expression(frame, calc.condition_right(statement))
+
+def eval_expression(frame, statement):
+ debug("EXPRESSION", statement)
+ if calc.isconstant(statement):
+ if not (type(statement) is int or type(statement) is float):
+ print("{} is not a valid constant, need to be either int or float"
+ .format(statement))
+ sys.exit(-1)
+ return statement
+ elif calc.isvariable(statement):
+ if statement not in frame:
+ print("variable {} not declared", statement)
+ sys.exit(-1)
+ return frame[statement]
+ elif calc.isbinary(statement):
+ return eval_binary(frame, statement)
+ else:
+ print("{} is not valid syntax".format(statement))
+ sys.exit(-1)
+
+def eval_assignment(frame, statement):
+ debug("ASSIGNMENT", statement)
+ new_frame = frame.copy()
+ new_frame[calc.assignment_variable(statement)] = \
+ eval_expression(frame, calc.assignment_expression(statement))
+ return new_frame
+
+def eval_condition(frame, statement):
+ debug("CONDITION", statement)
+ op = calc.condition_operator(statement)
+ if op == ">":
+ return eval_expression(frame, calc.condition_left(statement)) \
+ > eval_expression(frame, calc.condition_right(statement))
+ elif op == "<":
+ return eval_expression(frame, calc.condition_left(statement)) \
+ < eval_expression(frame, calc.condition_right(statement))
+ elif op == "=":
+ return eval_expression(frame, calc.condition_left(statement)) \
+ == eval_expression(frame, calc.condition_right(statement))
+ else:
+ print("{} is not valid syntax".format(statement))
+ sys.exit(-1)
+
+def eval_repetition(frame, statement):
+ debug("REPETITION", statement)
+ new_frame = frame.copy()
+ while eval_condition(new_frame, calc.repetition_condition(statement)):
+ new_frame = eval_statements(new_frame, calc.repetition_statements(statement))
+ return new_frame
+
+def eval_selection(frame, statement):
+ debug("SELECTION", statement)
+ new_frame = frame.copy()
+ if eval_condition(frame, calc.selection_condition):
+ new_frame = eval_statement(frame, calc.selection_true(statement))
+ elif calc.hasfalse(statement):
+ new_frame = eval_statement(frame, calc.selection_false(statement))
+ return new_frame
+
+def eval_input(frame, statement):
+ debug("INPUT", statement)
+ new_frame = frame.copy()
+ var = calc.input_variable(statement)
+ val = input("Enter value for {}: ".format(var))
+ try:
+ new_frame[var] = int(val)
+ except ValueError:
+ try:
+ new_frame[var] = float(val)
+ except ValueError:
+ pass #TODO
+ return new_frame
+
+def eval_output(frame, statement):
+ debug("OUTPUT", statement)
+ var = calc.output_variable(statement)
+ val = frame[var]
+ print("{} = {}".format(var, val))
+
+def eval_statement(frame, statement):
+ debug("STATEMENT", statement)
+ new_frame = frame.copy()
+ if calc.isassignment(statement):
+ new_frame = eval_assignment(frame, statement)
+ elif calc.isrepetition(statement):
+ new_frame = eval_repetition(frame, statement)
+ elif calc.isselection(statement):
+ new_frame = eval_selection(frame, statement)
+ elif calc.isinput(statement):
+ new_frame = eval_input(frame, statement)
+ elif calc.isoutput(statement):
+ eval_output(frame, statement)
+ else:
+ print("{} is not valid syntax".format(statement))
+ sys.exit(-1)
+ return new_frame
+
+def eval_statements(frame, statements):
+ debug("STATEMENTS", statements)
+ new_frame = eval_statement(frame, calc.first_statement(statements))
+ if calc.empty_statements(calc.rest_statements(statements)):
+ return new_frame
+ else:
+ return eval_statements(new_frame, calc.rest_statements(statements))
+
+def eval_program(program):
+ if not calc.isprogram(program):
+ return
+ statements = calc.program_statements(program)
+ return eval_statements({}, statements)