diff options
| author | Gustav Sörnäs <gustav@sornas.net> | 2020-03-22 02:11:32 +0100 |
|---|---|---|
| committer | Gustav Sörnäs <gustav@sornas.net> | 2020-03-22 02:11:32 +0100 |
| commit | 524294019eb859a2e9ad07ffb1cf5f0574db6024 (patch) | |
| tree | d5853f7870959faa84bf23e24d813fcda73ca4d5 | |
| download | tdde24-524294019eb859a2e9ad07ffb1cf5f0574db6024.tar.gz | |
add kod labb6
| -rw-r--r-- | l6/calc.py | 187 | ||||
| -rw-r--r-- | l6/kod.py | 133 |
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) |
