From 67f3cf39fad259b5a096b488a55b1482302350ee Mon Sep 17 00:00:00 2001 From: Abdur-Rahmaan Janhangeer Date: Wed, 24 Aug 2022 10:55:34 +0400 Subject: [PATCH] feat(package): init --- MANIFEST.in | 5 + setup.cfg | 11 + setup.py | 92 +++ src/greenberry/__init__.py | 0 src/greenberry/debug_cp.py | 12 + src/greenberry/gb.py | 333 ++++++++ src/greenberry/gb_ide.py | 623 +++++++++++++++ src/greenberry/gb_main.py | 27 + src/greenberry/gb_repl.py | 28 + src/greenberry/gb_utils/__init__.py | 0 src/greenberry/gb_utils/greenberry_lex.py | 43 + src/greenberry/gb_utils/greenberry_parse.py | 41 + src/greenberry/gb_utils/greenberry_plot.py | 57 ++ src/greenberry/gb_utils/greenberry_print.py | 51 ++ src/greenberry/gb_utils/greenberry_search.py | 93 +++ .../gb_utils/greenberry_var_type.py | 82 ++ src/greenberry/gbsymbols/__init__.py | 0 src/greenberry/gbsymbols/symbols.py | 58 ++ src/greenberry/gbtest/__init__.py | 0 src/greenberry/gbtest/lang_test.py | 61 ++ src/greenberry/gbtest/utils_test.py | 22 + src/greenberry/gbtools/__init__.py | 0 src/greenberry/gbtools/lexer.py | 78 ++ src/greenberry/gbtools/parser.py | 0 src/greenberry/greenberry_lex_test.py | 73 ++ src/greenberry/main.gb | 41 + src/greenberry/math.py | 24 + src/greenberry/symbols.py | 109 +++ src/greenberry/test.gb | 19 + src/greenberry/theory_notes_simple.py | 737 ++++++++++++++++++ src/greenberry/utils.py | 116 +++ src/greenberry/x.txt | 1 + src/greenberry/y.txt | 1 + 33 files changed, 2838 insertions(+) create mode 100644 MANIFEST.in create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 src/greenberry/__init__.py create mode 100644 src/greenberry/debug_cp.py create mode 100644 src/greenberry/gb.py create mode 100644 src/greenberry/gb_ide.py create mode 100644 src/greenberry/gb_main.py create mode 100644 src/greenberry/gb_repl.py create mode 100644 src/greenberry/gb_utils/__init__.py create mode 100644 src/greenberry/gb_utils/greenberry_lex.py create mode 100644 src/greenberry/gb_utils/greenberry_parse.py create mode 100644 src/greenberry/gb_utils/greenberry_plot.py create mode 100644 src/greenberry/gb_utils/greenberry_print.py create mode 100644 src/greenberry/gb_utils/greenberry_search.py create mode 100644 src/greenberry/gb_utils/greenberry_var_type.py create mode 100644 src/greenberry/gbsymbols/__init__.py create mode 100644 src/greenberry/gbsymbols/symbols.py create mode 100644 src/greenberry/gbtest/__init__.py create mode 100644 src/greenberry/gbtest/lang_test.py create mode 100644 src/greenberry/gbtest/utils_test.py create mode 100644 src/greenberry/gbtools/__init__.py create mode 100644 src/greenberry/gbtools/lexer.py create mode 100644 src/greenberry/gbtools/parser.py create mode 100644 src/greenberry/greenberry_lex_test.py create mode 100644 src/greenberry/main.gb create mode 100644 src/greenberry/math.py create mode 100644 src/greenberry/symbols.py create mode 100644 src/greenberry/test.gb create mode 100644 src/greenberry/theory_notes_simple.py create mode 100644 src/greenberry/utils.py create mode 100644 src/greenberry/x.txt create mode 100644 src/greenberry/y.txt diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..7171b01 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,5 @@ +include README.md +recursive-include reqs * +recursive-include src/greenberry * +global-exclude *.py[cod] +global-exclude __pycache__ diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..d307df5 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,11 @@ +[metadata] +description-file = README.md + +[options] +packages = find: +package_dir = = src +include_package_data = True +python_requires = >= 3.7 + +[options.packages.find] +where=src diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..3e4556b --- /dev/null +++ b/setup.py @@ -0,0 +1,92 @@ +"""A setuptools based setup module. +See: +https://packaging.python.org/guides/distributing-packages-using-setuptools/ +https://github.com/pypa/sampleproject +python setup.py publish to publish +""" + +import glob +import os +import sys + +import setuptools + +# Always prefer setuptools over distutils +from setuptools import find_packages +from setuptools import setup + +# from setuptools import find_packages + + +here = os.path.abspath(os.path.dirname(__file__)) + + +if sys.argv[-1] == "publish": # requests + os.system("python setup.py sdist") # bdist_wheel + os.system("twine upload dist/* --skip-existing") + sys.exit() + +# Get the long description from the README file +with open(os.path.join(here, "README.md"), encoding="utf-8") as f: + long_description = f.read() +setup( + name="greenberry", # Required + version="0.9.0", # Required + description="lang compiler-theory interpreter", # Optional + long_description=long_description, # Optional + long_description_content_type="text/markdown", # Optional (see note above) + url="https://github.com/Abdur-RahmaanJ/greenBerry", # Optional + author="Abdur-Rahmaan Janhangeer & contributors", # Optional + author_email="arj.python@gmail.com", # Optional + # Classifiers help users find your project by categorizing it. + # + # For a list of valid classifiers, see https://pypi.org/classifiers/ + classifiers=[ # Optional + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + "Development Status :: 4 - Beta", + # Indicate who your project is intended for + "Intended Audience :: Developers", + # 'Topic :: Weather', + # Pick your license as you wish + "License :: OSI Approved :: MIT License", + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + # These classifiers are *not* checked by 'pip install'. See instead + # 'python_requires' below. + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + ], + keywords="flask pos management shop ecommerce cms erp", # Optional + # You can just specify package directories manually here if your project is + # simple. Or you can use find_packages(). + # + # Alternatively, if you just want to distribute a single Python file, use + # the `py_modules` argument instead as follows, which will expect a file + # called `my_module.py` to exist: + # + # py_modules=["my_module"], + # + # packages=find_packages(exclude=['contrib', 'docs', 'tests']), # Required + python_requires=">=3.4", + include_package_data=True, + install_requires=open(os.path.join(here, "reqs", "app.txt"), encoding="utf-8") + .read() + .split("\n"), # Optional + extras_require={ + "dev": open(os.path.join(here, "reqs", "dev.txt"), encoding="utf-8") + .read() + .split("\n"), + }, + project_urls={ # Optional + "Bug Reports": "https://github.com/Abdur-RahmaanJ/greenBerry/issues", + "Source": "https://github.com/Abdur-RahmaanJ/greenBerry/", + }, + packages=find_packages(), + entry_points={"console_scripts": ["greenberry=greenberry.gb_main:main"]}, +) diff --git a/src/greenberry/__init__.py b/src/greenberry/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/greenberry/debug_cp.py b/src/greenberry/debug_cp.py new file mode 100644 index 0000000..8e99ccc --- /dev/null +++ b/src/greenberry/debug_cp.py @@ -0,0 +1,12 @@ +class Debug_cp: + """ + controled debugger logging module better + """ + + def __init__(self, name): + self.name = name + self.var = 1 + + def run(self): + print(self.name, "*** entered cp", self.var) + self.var += 1 diff --git a/src/greenberry/gb.py b/src/greenberry/gb.py new file mode 100644 index 0000000..8f061ed --- /dev/null +++ b/src/greenberry/gb.py @@ -0,0 +1,333 @@ +""" +Created on Tue Dec 26 21:53:56 2017 + +Notes : see +see theory_notes_simple.py +""" + +import inspect +from collections import OrderedDict + +from greenberry.debug_cp import * +from greenberry.gb_utils.greenberry_lex import GreenBerryLex +from greenberry.gb_utils.greenberry_parse import GreenBerryParse +from greenberry.gb_utils.greenberry_plot import GreenBerryPlot +from greenberry.gb_utils.greenberry_print import GreenBerryPrint +from greenberry.gb_utils.greenberry_search import GreenBerrySearch +from greenberry.gb_utils.greenberry_var_type import GreenBerryVarType +from greenberry.symbols import * + +L_USER = "dear berry" + + +# another lex would be to identify blobks first this is a side effect +MATH_OPS = ["+", "-", "*", "/"] +BOOLS = [S.TRUE, S.FALSE] +BOOL_OPS = [S.GREATER, S.LESS] +EOS = [S.NL, S.EOF] + +""" +Function with nested functions with different core +greenberry functionalities + +""" + + +def greenBerry_eval(x): + global L_USER + ### + # program starts here + ### + + M.g_vars = {} + M.g_fs = {} + M.g_cls = {} + F.bStart = 100 + F.bEnd = 0 + F.isDebugOn = 0 # this is a reset needed for gb_ide + + KWDs = [ + getattr(S, i) + for i in [ + b[0] + for b in [ + a + for a in inspect.getmembers(S, lambda a: not inspect.isroutine(a)) + if not (a[0].startswith("__") and a[0].endswith("__")) + ] + ] + ] + + g_vars = M.g_vars + g_fs = M.g_fs + g_cls = M.g_cls + words = GreenBerryLex.lex(x, KWDs, add_eof=1) + GreenBerryPrint.printd(words) + line = 1 + + """ + if elem.value == S.NL + error : elem.line + """ + for i, elem in enumerate(words): # mainloop for complex parsing + # printd(elem) + + # + # newline + # + if elem == S.NL: + line += 1 + + # + # minified for loop + # + elif elem == S.FOR: + try: + F.bStart = i + + times_by = int(words[i + 1]) + string = GreenBerrySearch.search(i, 3, words, [S.NL, S.EOF]) + wds = GreenBerryLex.lex(string, KWDs) + GreenBerryPrint.printd(wds) + for d in range(times_by): + GreenBerryParse.simple_parse(g_vars, wds, line) + # colon_i = search_symbol(i, 1, words, [S.COLON])[1] + F.bEnd = GreenBerrySearch.search_symbol(i, 1, words, [S.NL, S.EOF])[1] + except: + print(E.FOR, line) + + # + # if statement + # + elif elem == S.IF: # to be rededefined + try: + F.bStart = i + L, R = 0, 0 + raw = GreenBerrySearch.search_symbol( + i, + 1, + words, + [S.EQUAL, S.LESS, S.GREATER, S.EQUAL_GREATER, S.EQUAL_LESS], + ) + symbol = raw[0] + symbol_i = raw[1] + colon_i = GreenBerrySearch.search_symbol(i, 1, words, S.COLON)[1] + to_do = GreenBerrySearch.search(colon_i, 0, words, [S.NL, S.EOF]) + wds = GreenBerryLex.lex(to_do, KWDs) + if words[i + 1] == S.VAR_REF: + # print('L @ detected') + L = g_vars[words[i + 2]][0] + elif words[i + 1].isdigit(): + # print('L int detected') + L = int(words[i + 1]) + else: + # print('L str detected') + L = GreenBerrySearch.search(i, 0, words, [symbol, S.COLON]) + + if words[symbol_i + 1] == S.VAR_REF: + # print('R @ detected') + R = g_vars[words[symbol_i + 2]][0] + elif words[symbol_i + 1].isdigit(): + # print("R", words[symbol_i+1]) + R = int(words[symbol_i + 1]) + else: + # print('R str detected') + R = GreenBerrySearch.search(symbol_i, 0, words, [S.COLON]) + # print(L, R, symbol) + if symbol == S.EQUAL: + if L == R: + GreenBerryParse.simple_parse(g_vars, wds, line) + elif symbol == S.GREATER: + if L > R: + GreenBerryParse.simple_parse(g_vars, wds, line) + elif symbol == S.LESS: + if L < R: + GreenBerryParse.simple_parse(g_vars, wds, line) + elif symbol == S.EQUAL_GREATER: + if L >= R: + GreenBerryParse.simple_parse(g_vars, wds, line) + elif symbol == S.EQUAL_LESS: + if L <= R: + GreenBerryParse.simple_parse(g_vars, wds, line) + # colon_i = search_symbol(i, 1, words, [S.COLON])[1] + F.bEnd = GreenBerrySearch.search_symbol(i, 1, words, [S.NL, S.EOF])[1] + except: + print(E.IF, line) + + # resolve flag + # + # function definition + # + elif elem == S.FUNCDEF: # func vector : print aaa #func vector x : print @x + params = [] + try: + + F.bStart = i + func_name = words[i + 1] + if words[i + 2] == S.COLON: + body = GreenBerrySearch.search(i, 2, words, [S.NL, S.EOF]) + g_fs[func_name] = {"params": None, "body": body} + else: + params = GreenBerrySearch.search_toks(i, 1, words, [S.COLON]) + col_i = GreenBerrySearch.search_symbol(i, 1, words, [S.COLON])[1] + body = GreenBerrySearch.search(col_i, 0, words, [S.NL, S.EOF]) + registry = OrderedDict() + for param in params: + registry[param] = None + g_fs[func_name] = {"params": registry, "body": body} + + # colon_i = search_symbol(i, 1, words, [S.COLON])[1] + F.bEnd = GreenBerrySearch.search_symbol(i, 1, words, [S.NL, S.EOF])[1] + except: + print(E.FUNCDEF, line) + # + # function call + # + elif elem == S.FUNCCALL: # call vector + try: + func_name = words[i + 1] + if g_fs[func_name]["params"] is None: + # print(g_fs) + # print(func_name) + wds = GreenBerryLex.lex(g_fs[func_name]["body"], KWDs) + GreenBerryParse.simple_parse(g_vars, wds, line) + else: + param_vals = GreenBerrySearch.search_toks( + i, 1, words, [S.NL, S.EOF] + ) + registry = g_fs[func_name]["params"] + i = 0 + for key in registry: + registry[key] = [ + param_vals[i], + GreenBerryVarType.var_type(param_vals[i]), + ] # data + i += 1 + wds = lex(g_fs[func_name]["body"], KWDs) + GreenBerryParse.simple_parse(registry, wds, line) + except: + print(E.FUNCCALL, line) + + # + # class definition + # + elif elem == S.CLASS: # class Man : power = 10 action walk : print a + # attrs = {} future + try: + F.bStart = i + + class_name = words[ + i + 1 + ] # subsequent changed to action for mult attribs + attr_name = words[ + i + 3 + ] # search_symbol var_data(i+4, words, [S.NL, S.EOF]) + attr_val = GreenBerryVarType.var_data(i + 4, words, [S.ACTION]) + action_name = words[i + 7] + action_body = GreenBerrySearch.search(i + 7, 1, words, [S.NL, S.EOF]) + g_cls[class_name] = { + "attributes": {attr_name: attr_val}, + "actions": {action_name: action_body}, + } + + # colon_i = search_symbol(i, 1, words, [S.COLON])[1] + F.bEnd = GreenBerrySearch.search_symbol(i, 1, words, [S.NL, S.EOF])[1] + """ + class_name = { + name = name, + attributes = { + x = 1, + y = 2 + } + methods = { + walk = string here, + raise hand = string here + } + } + """ + except: + print(E.CLASSDEC, line) + + # + # call class method. + # + elif elem == S.MAKE: # make Man walk + try: + class_name = words[i + 1] + if class_name not in g_cls: + print("wrong class name berry") + action_name = words[i + 2] + raw_text = g_cls[class_name]["actions"][action_name] + wds = GreenBerryLex.lex(raw_text, KWDs) + GreenBerryParse.simple_parse(g_vars, wds, line) + except: + print(E.CLASSACT, line) + + # + # attribute viewing + # + elif elem == S.SEE: # see power of Man + try: + attr = words[i + 1] + class_name = words[i + 2] + print(g_cls[class_name]["attributes"][attr][0]) + except: + print(E.CLASSATT, line) + + # + # add attribute to class + # + elif elem == S.ADD: # add to Man attribute name = string i am me + try: + F.bStart = i + if words[i + 1] in g_cls: + if words[i + 2] == S.ATTRIB: + if words[i + 4] == S.EQUAL: + value = GreenBerryVarType.var_data( + i + 4, words, [S.NL, S.EOF] + ) + g_cls[words[i + 1]]["attributes"][words[i + 3]] = value + else: + print(E.EQUAL, line) + elif ( + words[i + 2] == S.ACTION + ): # add to Man action run : print running... + if words[i + 4] == S.COLON: + g_cls[words[i + 1]]["actions"][ + words[i + 3] + ] = GreenBerrySearch.search(i, 4, words, [S.NL, S.EOF]) + else: + print(E.COLON, line) + + else: + print(E.CLASSNAME, line) + F.bEnd = GreenBerrySearch.search_symbol(i, 1, words, [S.NL, S.EOF])[1] + except: + print(E.ADD, line) + + # + # debug on or off + # + elif elem == S.SET: # set debug on - set debug off + try: + if words[i + 1] == "debug": + if words[i + 2] == "on": + F.isDebugOn = 1 + elif words[i + 2] == "off": + F.isDebugOn = 0 + except: + print(E.DEBUG, line) + else: + if i < F.bStart or i > F.bEnd and elem != S.EOF: + F.bStart = i + F.bEnd = GreenBerrySearch.search_symbol(i, 1, words, [S.NL, S.EOF])[1] + to_do = GreenBerrySearch.search(i - 1, 0, words, [S.NL, S.EOF]) + wds = GreenBerryLex.lex(to_do, KWDs) + GreenBerryParse.simple_parse(g_vars, wds, line) + + GreenBerryPrint.printd(g_vars) + GreenBerryPrint.printd(g_fs) + GreenBerryPrint.printd(g_cls) + + +# python greenBerry_REPL.py diff --git a/src/greenberry/gb_ide.py b/src/greenberry/gb_ide.py new file mode 100644 index 0000000..2da2ea5 --- /dev/null +++ b/src/greenberry/gb_ide.py @@ -0,0 +1,623 @@ +import subprocess +import tkinter as tk +import tkinter.scrolledtext as tkst +from tkinter import filedialog +from tkinter import messagebox +from tkinter import simpledialog + +color1 = ["var", "print", "set", "debug", "plot"] +color2 = ["string", "eval", "times", "action", "attribute", "bool"] +color3 = ["=", "<", "<=", ">", ">=", "if", "for"] +color4 = ["@"] +color5 = ["make", "see", "add", "class", "func", "call"] + + +###### needed for line numbers ###### +class TextLineNumbers(tk.Canvas): + def __init__(self, *args, **kwargs): + tk.Canvas.__init__(self, *args, **kwargs) + self.textwidget = None + + def attach(self, text_widget): + self.textwidget = text_widget + + def redraw(self, *args): + self.delete("all") + + i = self.textwidget.index("@0,0") + + while True: + dline = self.textwidget.dlineinfo(i) + if dline is None: + break + y = dline[1] + linenum = str(i).split(".")[0] + self.create_text(2, y, anchor="nw", text=linenum) + i = self.textwidget.index("%s+1line" % i) + + +class CustomText(tk.Text): + def __init__(self, *args, **kwargs): + tkst.ScrolledText.__init__(self, *args, **kwargs) + + self._orig = self._w + "_orig" + self.tk.call("rename", self._w, self._orig) + self.tk.createcommand(self._w, self._proxy) + + def _proxy(self, *args): + try: + cmd = (self._orig,) + args + result = self.tk.call(cmd) + + if ( + args[0] in ("insert", "replace", "delete") + or args[0:3] == ("mark", "set", "insert") + or args[0:2] == ("xview", "moveto") + or args[0:2] == ("xview", "scroll") + or args[0:2] == ("yview", "moveto") + or args[0:2] == ("yview", "scroll") + ): + self.event_generate("<>", when="tail") + + return result + + except: # this prevents error '_tkinter.TclError: text doesn't contain any characters tagged with "sel"' + pass + + +###### needed for line numbers ###### + + +class MessageBox(tk.simpledialog.Dialog): + """Similar to tk.messagebox but updates parent if destroyed""" + + def __init__(self, parent, title, message): + self.messageText = message + tk.simpledialog.Dialog.__init__(self, parent, title) + + def body(self, master): + self.frame = tk.Frame(master) + self.message = tk.Message(self.frame, text=self.messageText) + self.btn_cancel = tk.Button(self.frame, text="Cancel", command=self.cancel) + self.bind("", self.cancel) + + self.frame.grid(column=0, row=0, sticky="NSEW") + self.message.grid(column=0, row=1) + self.btn_cancel.grid(column=0, row=2) + + return self.btn_cancel + + def destroy(self): + """Update parent when destroyed""" + self.parent.messageOpen = False + super().destroy() + + def buttonbox(self): + """Override default simpledialog.Dialog buttons""" + pass + + +class SearchDialog(tk.simpledialog.Dialog): + """Dialog for text find and replace""" + + def __init__(self, parent, txt, old_text, title="Find and replace"): + self.txt = txt + self.messageOpen = False + self.messageRef = None + tk.simpledialog.Dialog.__init__(self, parent, title) + + def body(self, master): + """Create dialog body, return widget with initial focus""" + + # Vars + self.search_text = tk.StringVar() + self.replace_text = tk.StringVar() + self.isCaseSensitive = tk.IntVar() + self.isCaseSensitive.set(1) + self.isBackward = tk.IntVar() + self.isRegExp = tk.IntVar() + self.matchLength = tk.IntVar() + + # Widgets + self.frame = tk.Frame(master) + self.frame_btn = tk.Frame(self.frame) + self.frame_check = tk.Frame(self.frame) + self.frame_entry = tk.Frame(self.frame) + self.search_entry = tk.Entry( + self.frame_entry, width=20, textvariable=self.search_text + ) + self.replace_entry = tk.Entry( + self.frame_entry, width=20, textvariable=self.replace_text + ) + self.check_case = tk.Checkbutton( + self.frame_check, text="Case sensitive", var=self.isCaseSensitive + ) + self.check_search_backward = tk.Checkbutton( + self.frame_check, text="Search backward", var=self.isBackward + ) + self.check_regexp = tk.Checkbutton( + self.frame_check, text="Use regular expression", var=self.isRegExp + ) + self.btn_search = tk.Button(self.frame_btn, text="Find", command=self.search) + self.btn_replace = tk.Button( + self.frame_btn, text="Replace", command=self.replace + ) + self.btn_search_and_replace = tk.Button( + self.frame_btn, text="Find and Replace", command=self.search_and_replace + ) + self.btn_cancel = tk.Button(self.frame, text="Cancel", command=self.cancel) + + # Frame placements + self.frame.grid(column=0, row=0, sticky="NSEW") + self.btn_cancel.grid(column=1, row=1, sticky="E", padx=(4, 8), pady=(4, 8)) + + self.frame_entry.grid(column=0, row=0) + tk.Label(self.frame_entry, text="Find:").grid(column=0, row=0, sticky="W") + self.search_entry.grid(column=1, row=0) + tk.Label(self.frame_entry, text="Replace:").grid( + column=0, row=1, sticky="W", pady=(6, 12) + ) + self.replace_entry.grid(column=1, row=1, pady=(6, 12)) + + self.frame_btn.grid(column=0, row=1, padx=(8, 4), pady=(4, 8)) + self.btn_search.grid(column=0, row=0, sticky="W") + self.btn_replace.grid(column=1, row=0, sticky="W", padx=(2, 10)) + self.btn_search_and_replace.grid(column=2, row=0, sticky="E") + + self.frame_check.grid(column=1, row=0, pady=(6, 12)) + self.check_case.grid(column=0, row=0, sticky="W") + self.check_search_backward.grid(column=0, row=1, sticky="W") + self.check_regexp.grid(column=0, row=2, sticky="W") + + return self.search_entry + + def _createMessage(self, text): + """Create MessageBox, update state; recreate if already open""" + if self.messageOpen: + self._destroyMessage() + self.messageRef = MessageBox(self, title="", message=text) + self.messageOpen = True + + def _destroyMessage(self): + """Destroy MessageBox and update message state""" + if self.messageOpen: + self.messageRef.destroy() + self.messageRef = None + self.messageOpen = False + + def _searchData(self): + """Return snapshot of dialog vars relevant to _search""" + return { + "caseSensitive": self.isCaseSensitive.get(), + "backwards": self.isBackward.get(), + "regexp": self.isRegExp.get(), + "search_text": self.search_text.get(), + "replace_text": self.replace_text.get(), + } + + def _search(self, doSearch, doReplace): + """Internal method to search and/or replace""" + if not doSearch and not doReplace: + return + + self.txt.tag_configure("found", background="#aaaaaa") + self.txt.tag_configure("replaced", background="#aaaaaa") + data = self._searchData() + n_search = len(data["search_text"]) + if doSearch and not n_search > 0: + return + + if doSearch: + if data["backwards"]: + self.txt.mark_set("search_start", "insert") + self.txt.mark_set("search_end", "1.0" + "-1c") + else: + self.txt.mark_set("search_start", "insert") + self.txt.mark_set("search_end", "end") + + if data["caseSensitive"]: + nocase = 0 + else: + nocase = 1 + + if data["regexp"]: + start = self.txt.search( + r"{}".format(data["search_text"]), + self.txt.index("search_start"), + stopindex=self.txt.index("search_end"), + backwards=data["backwards"], + count=self.matchLength, + nocase=nocase, + regexp=True, + ) + else: + start = self.txt.search( + data["search_text"], + self.txt.index("search_start"), + stopindex=self.txt.index("search_end"), + backwards=data["backwards"], + count=self.matchLength, + nocase=nocase, + ) + if start: + end = start + f"+{self.matchLength.get()}c" + self.txt.tag_add("found", start, end) + if data["backwards"]: + self.txt.mark_set("insert", start) + else: + self.txt.mark_set("insert", end) + else: # if no results found + self._createMessage("No matches found.") + return + + if doReplace: + foundRanges = self.txt.tag_ranges("found") + if not foundRanges: + # If no 'found' tags, then do a search instead + self._search(doSearch=True, doReplace=False) + return + foundStarts = [idx for i, idx in enumerate(foundRanges) if i % 2 == 0] + foundEnds = [idx for i, idx in enumerate(foundRanges) if i % 2 == 1] + for foundStart, foundEnd in zip(foundStarts, foundEnds): + self.txt.delete(foundStart, foundEnd) + self.txt.insert(foundStart, data["replace_text"], ("replaced",)) + + def search(self, event=0): + """Command for Search button""" + self._search(doSearch=True, doReplace=False) + + def replace(self, event=0): + """Command for Replace button""" + self._search(doSearch=False, doReplace=True) + + def search_and_replace(self, event=0): + """Command for Search and Replace button""" + self._search(doSearch=True, doReplace=True) + + def destroy(self): + """Add text tag cleanup to simpledialog.Dialog destroy""" + self.txt.tag_remove("found", "1.0", "end") + self.txt.tag_remove("replaced", "1.0", "end") + super().destroy() + + def buttonbox(self): + """Override default simpledialog.Dialog buttons""" + pass + + +class Files(tk.Frame): + def __init__(self, parent): + tk.Frame.__init__(self, parent) + + self.parent = parent + parent.protocol("WM_DELETE_WINDOW", self.wclose) + + self.parent.title("greenBerry IDE - Untitled") + self.pack(fill="both", expand=True) + + menubar = tk.Menu(self.parent) + self.parent.config(menu=menubar) + + fileMenu = tk.Menu(menubar) + runMenu = tk.Menu(menubar) + searchMenu = tk.Menu(menubar) + fileMenu.add_command(label="Save", command=self.save_file, accelerator="Ctrl+S") + fileMenu.add_command( + label="Save As", command=self.save_as_command, accelerator="Ctrl+Shift+S" + ) + fileMenu.add_command(label="Open", command=self.open_file, accelerator="Ctrl+O") + menubar.add_cascade(label="File", menu=fileMenu) + + runMenu.add_command(label="Run", command=self.run_command, accelerator="F5") + menubar.add_cascade(label="Run", menu=runMenu, command=self.open_file) + + searchMenu.add_command( + label="Find and replace", command=self.search_command, accelerator="Ctrl+F" + ) + menubar.add_cascade(label="Search", menu=searchMenu) + + self.bind_all("", self.run_command) + self.bind_all("", self.open_file) + self.bind_all("", self.save_file) + self.bind_all("", self.save_as_command) + self.bind_all("", self.search_command) + self.bind_all("", self.key_pressed) + + self.run_button = tk.Button(root, command=self.run_command) + self.run_photo = tk.PhotoImage(file="../docs/run_button.png") + self.run_button.config(image=self.run_photo, height=20, width=20) + self.run_button.pack() + + self.txt = CustomText(self) + self.linenumbers = TextLineNumbers(self, width=30) + self.linenumbers.attach(self.txt) + + self.linenumbers.pack(side="left", fill="y") + self.txt.pack(side="right", fill="both", expand=True) + + self.txt.bind("<>", self._on_change) + self.txt.bind("", self._on_change) + + self.old_text = self.txt.get("1.0", "end" + "-1c") + self.file_dir = "" + + self.first = True + + def _on_change(self, event): + self.linenumbers.redraw() + + def _on_change2(self, event): + self.linenumbers2.redraw() + + def key_pressed(self, event=0): + self.color_text() # run syntax highlighting + + a = self.parent.title() + + if self.txt.get("1.0", "end" + "-1c") != self.old_text and a[0] != "*": + self.parent.title("*" + self.parent.title()) + + elif self.txt.get("1.0", "end" + "-1c") == self.old_text and a[0] == "*": + self.parent.title(self.parent.title()[1:]) + + self.txt.yview_pickplace("insert") + + def open_file(self, event=0): + self.txt.delete("insert") # Ctrl+o causes a new line so we need to delete it + + ftypes = [("greenBerry files", "*.gb"), ("All files", "*")] + file = filedialog.askopenfile(filetypes=ftypes) + + if file != None: + self.file_dir = file.name + self.parent.title("greenBerry IDE" + " - " + file.name.replace("/", "\\")) + self.txt.delete("1.0", "end" + "-1c") + text = self.read_file(file.name) + self.txt.insert("end", text) + self.old_text = self.txt.get("1.0", "end" + "-1c") + self.key_pressed() + + def read_file(self, filename): + f = open(filename) + text = f.read() + return text + + def save_file(self, event=0): + try: + with open(self.file_dir, "w") as file: + file.write(self.txt.get("1.0", "end" + "-1c")) + file.close() + self.old_text = self.txt.get("1.0", "end" + "-1c") + self.key_pressed() + except: + self.save_as_command() + + def search_command(self, event=0): + d = SearchDialog( + self.parent, txt=self.txt, old_text=self.old_text, title="Find and replace" + ) + + def save_as_command(self, event=0): + file = filedialog.asksaveasfile( + mode="w", + defaultextension=".gb", + filetypes=(("greenBerry files", "*.gb"), ("All files", "*")), + ) + if file != None: + self.parent.title("greenBerry IDE" + " - " + file.name.replace("/", "\\")) + self.file_dir = file.name + data = self.txt.get("1.0", "end" + "-1c") + file.write(data) + file.close() + self.old_text = self.txt.get("1.0", "end" + "-1c") + + def run_command(self, event=0): + x = self.txt.get("1.0", "end" + "-1c") + + if x == self.old_text and x != "": + if self.first: + self.outwin = tk.Toplevel(root) + self.outwin.title("greenBerry IDE - output") + self.outwin.geometry("600x640") + + self.txtout = CustomText(self.outwin) + + self.linenumbers2 = TextLineNumbers(self.outwin, width=30) + self.linenumbers2.attach(self.txtout) + + self.linenumbers2.pack(side="left", fill="y") + self.txtout.pack(fill="both", expand=True) + + self.txtout.bind("<>", self._on_change2) + self.txtout.bind("", self._on_change2) + + proc = subprocess.Popen( + [ + "python", + "-c", + 'import greenberry; greenberry.gb.greenBerry_eval("""{}""")'.format( + self.read_file(self.file_dir) + ), + ], + stdout=subprocess.PIPE, + ) + out = proc.communicate()[0][:-2] + + self.txtout.config(state="normal") + if not self.first: + self.txtout.insert("end", "\n" + "=" * 25 + "NEW RUN" + "=" * 25 + "\n") + else: + self.first = False + self.txtout.insert("end", out) + self.txtout.config(state="disabled") + + self.txtout.tag_add("colorout", "1.0", "end") + self.txtout.tag_config("colorout", foreground="blue") + + self.txtout.yview_pickplace("end") + + elif messagebox.askokcancel( + "Save before run", + "Your file must be saved before running.\nPress OK to save.", + ): + self.save_file() + try: + if self.first: + self.outwin = tk.Toplevel(root) + self.outwin.title("greenBerry IDE - output") + self.outwin.geometry("600x640") + + self.txtout = CustomText(self.outwin) + + self.linenumbers2 = TextLineNumbers(self.outwin, width=30) + self.linenumbers2.attach(self.txtout) + + self.linenumbers2.pack(side="left", fill="y") + self.txtout.pack(fill="both", expand=True) + + self.txtout.bind("<>", self._on_change2) + self.txtout.bind("", self._on_change2) + + proc = subprocess.Popen( + [ + "python", + "-c", + 'import greenberry; greenberry.gb.greenBerry_eval("""{}""")'.format( + self.read_file(self.file_dir) + ), + ], + stdout=subprocess.PIPE, + ) + out = proc.communicate()[0][:-2] + + self.txtout.config(state="normal") + if not self.first: + self.txtout.insert( + "end", "\n" + "=" * 25 + "NEW RUN" + "=" * 25 + "\n" + ) + else: + self.first = False + self.txtout.insert("end", out) + self.txtout.config(state="disabled") + + self.txtout.tag_add("colorout", "1.0", "end") + self.txtout.tag_config("colorout", foreground="blue") + + self.txtout.yview_pickplace("end") + + except: + self.run_command() + + def wclose(self, event=0): + if self.parent.title()[0] == "*": + save = messagebox.askyesnocancel( + "Save file", + "You have unsaved changes.\nDo you want to save before closing?", + ) + + if save: + self.save_file() + if self.parent.title()[0] == "*": + self.wclose() + else: + root.destroy() + + elif not save: + root.destroy() + else: + root.destroy() + + def color_text(self, event=0): + file_text = self.txt.get("1.0", "end" + "-1c") + " " + words = [] + line = 1 + column = -1 + word = "" + + for char in file_text: + word += char + column += 1 + if char == "\n": + words.append(word[:-1] + " : " + str(line) + "." + str(column)) + word = "" + line += 1 + column = -1 + + if char == " ": + words.append(word[:-1] + " : " + str(line) + "." + str(column)) + word = "" + + for ( + tag + ) in self.txt.tag_names(): # deletes all tags so it can refresh them later + self.txt.tag_delete(tag) + + for i in words: + + i = i.split() + + if len(i) < 3: + i.insert(0, " ") + + if i[0] in color1: + self.txt.tag_add( + "color1", + str(i[2].split(".")[0]) + + "." + + str(int(i[2].split(".")[1]) - len(i[0])), + i[2], + ) + self.txt.tag_config("color1", foreground="#9a1777") + + elif i[0] in color2: + self.txt.tag_add( + "color2", + str(i[2].split(".")[0]) + + "." + + str(int(i[2].split(".")[1]) - len(i[0])), + i[2], + ) + self.txt.tag_config("color2", foreground="orange") + + elif i[0] in color3: + self.txt.tag_add( + "color3", + str(i[2].split(".")[0]) + + "." + + str(int(i[2].split(".")[1]) - len(i[0])), + i[2], + ) + self.txt.tag_config("color3", foreground="#e60000") + + elif i[0][0] in color4: + self.txt.tag_add( + "color4", + str(i[2].split(".")[0]) + + "." + + str(int(i[2].split(".")[1]) - len(i[0])), + str(i[2].split(".")[0]) + + "." + + str(int(i[2].split(".")[1]) - len(i[0]) + 1), + ) + self.txt.tag_config("color4", foreground="orange") + + elif i[0] in color5: + self.txt.tag_add( + "color5", + str(i[2].split(".")[0]) + + "." + + str(int(i[2].split(".")[1]) - len(i[0])), + i[2], + ) + self.txt.tag_config("color5", foreground="#00cc00") + + +root = tk.Tk() + +ex = Files(root) +ex.pack(side="bottom") + +root.geometry("600x640") +root.iconbitmap(default="../docs/favicon.ico") + +root.mainloop() diff --git a/src/greenberry/gb_main.py b/src/greenberry/gb_main.py new file mode 100644 index 0000000..e3770e9 --- /dev/null +++ b/src/greenberry/gb_main.py @@ -0,0 +1,27 @@ +""" +Created on Sun Dec 31 22:54:37 2017 + +@author: ARJ +""" + +import os +import sys + +from greenberry.gb import greenBerry_eval + + +def main(): + if len(sys.argv) == 2: + with open(os.path.join(os.getcwd(), sys.argv[1])) as f: + x = f.read() + + greenBerry_eval(x) + + +if __name__ == "__main__": + x = "" + + with open("main.gb") as f: + x = f.read() + + greenBerry_eval(x) diff --git a/src/greenberry/gb_repl.py b/src/greenberry/gb_repl.py new file mode 100644 index 0000000..8acd777 --- /dev/null +++ b/src/greenberry/gb_repl.py @@ -0,0 +1,28 @@ +""" +Created on Sun Dec 31 22:21:00 2017 + +@author: ARJ +""" +from greenberry.gb import greenBerry_eval + +print( + """ + ---greenBerry(c)--- + welcome to the .gb REPL + ---greenBerry(c)--- + """ +) +isSessionOn = 1 +while isSessionOn == 1: + x = input("---> ") + greenBerry_eval(x) + if x == "berry exit": + isSessionOn = 0 + print() +print( + """ + ---greenBerry(c)--- + .gb REPL exited. see you soon _ _ + ---greenBerry(c)--- + """ +) diff --git a/src/greenberry/gb_utils/__init__.py b/src/greenberry/gb_utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/greenberry/gb_utils/greenberry_lex.py b/src/greenberry/gb_utils/greenberry_lex.py new file mode 100644 index 0000000..857b7e3 --- /dev/null +++ b/src/greenberry/gb_utils/greenberry_lex.py @@ -0,0 +1,43 @@ +""" +Class for breaking strings into symbols +and return a list of each symbol. +""" +import inspect + +from greenberry.symbols import * + +L_USER = "dear berry" + +# another lex would be to identify blobks first this is a side effect +MATH_OPS = ["+", "-", "*", "/"] +BOOLS = [S.TRUE, S.FALSE] +BOOL_OPS = [S.GREATER, S.LESS] +EOS = [S.NL, S.EOF] + + +class GreenBerryLex: + def __init__(self): + print(self, "does not have an initialiser") + + def lex(x, KWDs, add_eof=""): + """ + breaks string into symbols and ids + returns list + + x - source string + KWDs - keywords/symbols + """ + words = [] + cup = "" + for i, elem in enumerate(x): + if elem != " ": + cup += elem + if i + 1 >= len(x) or x[i + 1] == " " or x[i + 1] in KWDs or elem in KWDs: + if cup != "": + words.append(cup) + cup = "" + + if add_eof == 1: + words.append(S.EOF) + + return words diff --git a/src/greenberry/gb_utils/greenberry_parse.py b/src/greenberry/gb_utils/greenberry_parse.py new file mode 100644 index 0000000..c0c3930 --- /dev/null +++ b/src/greenberry/gb_utils/greenberry_parse.py @@ -0,0 +1,41 @@ +import inspect +from collections import OrderedDict + +from greenberry.debug_cp import * +from greenberry.gb_utils.greenberry_plot import GreenBerryPlot +from greenberry.gb_utils.greenberry_print import GreenBerryPrint +from greenberry.gb_utils.greenberry_var_type import GreenBerryVarType +from greenberry.symbols import * + +L_USER = "dear berry" + +# another lex would be to identify blobks first this is a side effect +MATH_OPS = ["+", "-", "*", "/"] +BOOLS = [S.TRUE, S.FALSE] +BOOL_OPS = [S.GREATER, S.LESS] +EOS = [S.NL, S.EOF] + + +class GreenBerryParse: + def __init__(self): + print(self, "does not have an initialiser") + + def simple_parse(g_vars, words, line): + """ + parses simple statements + + variable assignment + print statement + ploting + + g_vars is a registry / dictionary storing variables + """ + for i, elem in enumerate(words): + if elem == S.VAR: + var_val = GreenBerryVarType.var_data(i + 2, words, [S.NL, S.EOF]) + g_vars[words[i + 1]] = var_val + elif elem == S.PRINT: + GreenBerryPrint.print_handling(g_vars, i, words) + elif elem == S.PLOT: + Plot = GreenBerryPlot() + Plot.plot_handling(i, words, line) diff --git a/src/greenberry/gb_utils/greenberry_plot.py b/src/greenberry/gb_utils/greenberry_plot.py new file mode 100644 index 0000000..075f49c --- /dev/null +++ b/src/greenberry/gb_utils/greenberry_plot.py @@ -0,0 +1,57 @@ +import inspect +from collections import OrderedDict + +from greenberry.debug_cp import * +from greenberry.gb_utils.greenberry_search import GreenBerrySearch +from greenberry.symbols import * + +L_USER = "dear berry" + +# another lex would be to identify blobks first this is a side effect +MATH_OPS = ["+", "-", "*", "/"] +BOOLS = [S.TRUE, S.FALSE] +BOOL_OPS = [S.GREATER, S.LESS] +EOS = [S.NL, S.EOF] + + +class GreenBerryPlot: + def __init__(self): + print(self, "does not have an initialiser") + + def linear_plot(self, dataX, labelX, dataY, labelY): + """simple line plot""" + try: + import matplotlib.pyplot as plt + + plt.plot(dataX, dataY) + plt.xlabel(labelX) + plt.ylabel(labelY) + plt.show() + except ImportError: + print("matplotlib unimported") + + def plot_handling(self, i, words, line): + """ + handles plotting of points + """ + try: + comma_i = GreenBerrySearch.search_symbol(i, 1, words, S.COMMA)[1] + if words[i + 1][0] != "'" and words[i + 1][0] != '"': + dataX = list(map(float, words[i + 1].split("-"))) + else: + file_name = words[i + 1][1:-1] + with open(file_name) as file: + dataX = list(map(float, file.read().split("-"))) + + if words[comma_i + 1][0] != "'" and words[comma_i + 1][0] != '"': + dataY = list(map(float, words[comma_i + 1].split("-"))) + else: + file_name = words[comma_i + 1][1:-1] + with open(file_name) as file: + dataY = list(map(float, file.read().split("-"))) + + labelX = GreenBerrySearch.search(i, 1, words, S.COMMA) + labelY = GreenBerrySearch.search(comma_i, 1, words, [S.NL, S.EOF]) + self.linear_plot(dataX, labelX, dataY, labelY) + except: + print(E.PLOT, line) diff --git a/src/greenberry/gb_utils/greenberry_print.py b/src/greenberry/gb_utils/greenberry_print.py new file mode 100644 index 0000000..18d2454 --- /dev/null +++ b/src/greenberry/gb_utils/greenberry_print.py @@ -0,0 +1,51 @@ +import inspect +from collections import OrderedDict + +from greenberry.debug_cp import * +from greenberry.gb_utils.greenberry_var_type import GreenBerrySearch +from greenberry.gb_utils.greenberry_var_type import GreenBerryVarType +from greenberry.symbols import * + +L_USER = "dear berry" + +MATH_OPS = ["+", "-", "*", "/"] +BOOLS = [S.TRUE, S.FALSE] +BOOL_OPS = [S.GREATER, S.LESS] +EOS = [S.NL, S.EOF] + + +class GreenBerryPrint: + def __init(self): + print(self, "does not have an initialiser") + + def printd(*args): + """ + custom debugger print + no return + """ + if F.isDebugOn: + for arg in args: + print(" " * 5, "@debug->", arg) + + def print_handling(g_vars, i, words): + """parses print command""" + try: + if i + 1 < len(words) and words[i + 1] not in [S.STRING, S.EVAL, S.VAR_REF]: + print(words[i + 1]) + elif i + 1 < len(words) and words[i + 1] == S.VAR_REF: + try: + print(GreenBerryVarType.var_ref_handling(i + 1, words, g_vars)) + except: + print(E.VARREF, line) + elif i + 1 < len(words) and words[i + 1] == S.EVAL: + try: + print(eval(words[i + 2])) + except: + print(E.EVAL, line) + elif i + 1 < len(words) and words[i + 1] == S.STRING: + try: + print(GreenBerrySearch.search(i, 1, words, [S.NL, S.EOF])) + except: + print(E.STRING, line) + except: + print(E.PRINT) diff --git a/src/greenberry/gb_utils/greenberry_search.py b/src/greenberry/gb_utils/greenberry_search.py new file mode 100644 index 0000000..139c608 --- /dev/null +++ b/src/greenberry/gb_utils/greenberry_search.py @@ -0,0 +1,93 @@ +import inspect +from collections import OrderedDict + +from greenberry.debug_cp import * +from greenberry.symbols import * + +L_USER = "dear berry" + +# another lex would be to identify blobks first this is a side effect +MATH_OPS = ["+", "-", "*", "/"] +BOOLS = [S.TRUE, S.FALSE] +BOOL_OPS = [S.GREATER, S.LESS] +EOS = [S.NL, S.EOF] + + +class GreenBerrySearch: + def __init(self): + print(self, "does not have an initialiser") + + def search(i, offset, words, delimeters): + """ + searches for symbols and returns string in between specified index + and symbol + + i - current index + offset - offset from index + words - current list of symbol/keyword being searched in + delimiters - list of delimiting symbols + + return string + """ + base = i + offset + j = 1 + string = "" + while base + j < len(words): + if words[base + j] in delimeters: + break + string += words[base + j] + " " + j += 1 + return string + + def search_toks(i, offset, words, delimeters): + """ + searches for symbols and returns all found sybols in between + specified index and symbol as list + + i - current index + offset - offset from index + words - current list of symbol/keyword being searched in + delimiters - list of delimiting symbols + + return list + """ + base = i + offset + j = 1 + list = [] + while base + j < len(words): + if words[base + j] in delimeters: + break + list.append(words[base + j]) + j += 1 + return list + + def search_symbol(i, offset, words, delimeters): # i to be resolved + """ + finds the index as well as the delimiting symbol (in case there are + many) we are searching for + + i - current index + offset - offset from index + words - current list of symbol/keyword being searched in + delimiters - list of delimiting symbols + word - symbol or set of symbols currently being checked + new_base - index to be returned after the search + + return list + + list[0] - symbol + list[1] - index + """ + base = i + offset + j = 1 + while base + j < len(words): + word = "".join(words[base + j : base + j + 2]) + new_base = base + j + 1 + if word in delimeters: + break + word = words[base + j] + new_base = base + j + if word in delimeters: + break + j += 1 + return [word, new_base] diff --git a/src/greenberry/gb_utils/greenberry_var_type.py b/src/greenberry/gb_utils/greenberry_var_type.py new file mode 100644 index 0000000..87153b7 --- /dev/null +++ b/src/greenberry/gb_utils/greenberry_var_type.py @@ -0,0 +1,82 @@ +import inspect +from collections import OrderedDict + +from greenberry.debug_cp import * +from greenberry.gb_utils.greenberry_search import GreenBerrySearch +from greenberry.symbols import * + +L_USER = "dear berry" + +# another lex would be to identify blobks first this is a side effect +MATH_OPS = ["+", "-", "*", "/"] +BOOLS = [S.TRUE, S.FALSE] +BOOL_OPS = [S.GREATER, S.LESS] +EOS = [S.NL, S.EOF] + + +class GreenBerryVarType: + def __init__(self): + print(self, "does not have an initialiser") + + def var_data(equal_i, words, delimeters): # var x = 1 + """recognises data type""" + value = 0 + type = None + if words[equal_i + 1] == S.STRING: + value = GreenBerrySearch.search(equal_i + 1, 0, words, delimeters) + type = "string" + elif words[equal_i + 1] == S.VAR_REF: + value = M.g_vars[words[equal_i + 2]][0] + type = "var_ref" + elif words[equal_i + 1].isdigit(): + value = words[equal_i + 1] + type = "number" + elif words[equal_i + 1] == S.SQL: + value = GreenBerrySearch.search(equal_i, 1, words, [S.SQR]) + type = "array" + elif words[equal_i + 1] == S.BOOL: + if words[equal_i + 2] == S.TRUE or words[equal_i + 2] == "1": + value = words[equal_i + 2] + type = "bool_1" + if words[equal_i + 2] == S.FALSE or words[equal_i + 2] == "0": + value = words[equal_i + 2] + type = "bool_0" + + else: + value = words[equal_i + 1] + type = "word" + return [value, type] + + def var_type(string): # var x = 1 + type = None + words = lex(string, KWDs) + if words[0] == S.STRING: + type = "string" + elif words[0] == S.VAR_REF: + type = "var_ref" + elif words[0].isdigit(): + type = "number" + elif words[0] == S.SQL: + type = "array" + elif words[0] == S.BOOL: + if words[1] == S.TRUE or words[1] == "1": + type = "bool_1" + if words[1] == S.FALSE or words[1] == "0": + type = "bool_0" + else: + type = "word" + return type + + def var_ref_handling(at_i, words, g_vars): # @y[1] + """recognises references to variables""" + name = words[at_i + 1] # class debug + type = g_vars[name][1] + value = g_vars[name][0] + returned_val = 0 + if type == "array" and len(words) > 3: + value = value.split(S.COMMA) + returned_val = value[int(words[at_i + 3])].strip() + else: + returned_val = value + + return returned_val diff --git a/src/greenberry/gbsymbols/__init__.py b/src/greenberry/gbsymbols/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/greenberry/gbsymbols/symbols.py b/src/greenberry/gbsymbols/symbols.py new file mode 100644 index 0000000..feb8c95 --- /dev/null +++ b/src/greenberry/gbsymbols/symbols.py @@ -0,0 +1,58 @@ +class S: # Symbols keywords + EOF = "{***end-of-file***}" + NL = "\n" + WS = " " + E = "" + + EQUAL = "=" + LESS = "<" + GREATER = ">" + COMMA = "," + SQL = "[" + SQR = "]" + + PRINT = "print" + + NUMBER = "number" + STRING = "string" + BOOL = "bool" + + TRUE = "true" + FALSE = "false" + + EVAL = "eval" + + VAR = "var" + VAR_REF = "@" + PLOT = "plot" + FOR = "for" + IF = "if" + COLON = ":" + FUNCDEF = "func" + FUNCCALL = "call" + CLASS = "class" + ACTION = "action" + COMMA = "," + IS = "is" + MAKE = "make" + ADD = "add" + TO = "to" + SEE = "see" + OF = "of" + SET = "set" + ATTRIB = "attribute" + TABLE = "table" + + # math + ODD = "odd" + EVEN = "even" + PRIME = "prime" + PI = "pi" + LOG = "log" + LOG10 = "log10" # log(x) returns the logarithm value of x + SQROOT = "sqroot" # sqroot(x) should return square root value of x + SQ = "square" # square(x) returns square value of x + TAN = "tan" # tan(x) returns tangent value of x + COS = "cos" # cos(x) returns cosine value of x + SIN = "sin" # sin(x) returns sine value of x + HYP = "hyp" # returns sqroot(x**2 + y**2), takes in two parameters diff --git a/src/greenberry/gbtest/__init__.py b/src/greenberry/gbtest/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/greenberry/gbtest/lang_test.py b/src/greenberry/gbtest/lang_test.py new file mode 100644 index 0000000..21f647d --- /dev/null +++ b/src/greenberry/gbtest/lang_test.py @@ -0,0 +1,61 @@ +# +# language tests +# + +import sys + +sys.path.append("..") + +import unittest + +from utils import capture_gb_eval_print + +from greenBerry import greenBerry_eval + + +class GBLangTests(unittest.TestCase): + def test_printd(self): + pass + + def test_null(self): + # check null input + x = "" + try: + greenBerry_eval(x) + except: + error = True + self.assertTrue(error) + + def test_eval_add(self): + x = "print eval 1+2" + output = capture_gb_eval_print(x) + self.assertEqual(output, "3") + + def test_eval_minus(self): + x = "print eval 3-2" + output = capture_gb_eval_print(x) + self.assertEqual(output, "1") + + def test_eval_times(self): + x = "print eval 3*2" + output = capture_gb_eval_print(x) + self.assertEqual(output, "6") + + def test_eval_divide(self): + x = "print eval 10/2" + output = capture_gb_eval_print(x) + self.assertEqual(output, "5.0") + + def test_eval_mixed_ops(self): + x = "print eval 1*3+10+3-2/2" + output = capture_gb_eval_print(x) + self.assertEqual(output, "15.0") + + def test_eval_mixed_ops(self): + x = "print eval 1*3+10+3-2/2+(3+2)" + output = capture_gb_eval_print(x) + self.assertEqual(output, "20.0") + + +if __name__ == "__main__": + unittest.main(exit=False) diff --git a/src/greenberry/gbtest/utils_test.py b/src/greenberry/gbtest/utils_test.py new file mode 100644 index 0000000..ef5eddd --- /dev/null +++ b/src/greenberry/gbtest/utils_test.py @@ -0,0 +1,22 @@ +# +# utils test +# + +import sys + +sys.path.append("..") + +import unittest + +from utils import capture_maths_eval_print + + +class GBUtilsTests(unittest.TestCase): + def test_maths_eval_add(self): + x = "3+2-1" + output = capture_maths_eval_print(x) + self.assertEqual(output, "4") + + +if __name__ == "__main__": + unittest.main(exit=False) diff --git a/src/greenberry/gbtools/__init__.py b/src/greenberry/gbtools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/greenberry/gbtools/lexer.py b/src/greenberry/gbtools/lexer.py new file mode 100644 index 0000000..5526cbc --- /dev/null +++ b/src/greenberry/gbtools/lexer.py @@ -0,0 +1,78 @@ +class Token: + def __init__(self, value, type, status, line): + self.value = value + self.type = type + self.status = status + self.line = line + + +class Lexeme: + def __init__(self, value, line): + self.value = value + self.line = line + + +class Lexer: + global ops + + def __init__(self, source, KWDs): + # parameters + self.source = source # text-file or string + self.KWDs = KWDs + + # data containers + self.cup = "" + self.lexemes = [] + self.tokens = [] + + # info + self.line = 1 + self.status = "" + + def get_lexemes(self): + for i, elem in enumerate(self.source): + if elem == S.NL: + self.line += 1 + if elem != S.WS: + self.cup += elem + if ( + i + 1 >= len(self.source) + or self.source[i + 1] == S.WS + or self.source[i + 1] in self.KWDs + or elem in self.KWDs + ): + if self.cup != S.E: + self.lexemes.append(Lexeme(self.cup, self.line)) + self.cup = S.E + return self.lexemes + + def get_tokens(self, lexemes): + for lexeme in lexemes: + type = "" + status = "" + isStringOn = 0 + isIfOn = 0 + + if lexeme.value in MATH_OPS: + type = "math operator" + elif lexeme.value in BOOL_OPS: + type = "bool operator" + elif lexeme.value in BOOLS: + type = "bool value" + elif lexeme.value == S.STRING: + isStringOn = 1 + type = "string" + elif lexeme.value == S.EQUAL: + if isIfOn == 1: + type = "equalto comparison" + else: + type = "assignment operator" + elif lexeme.value in EOS: # newline + isStringOn = 0 + isIfOn = 0 + + if isStringOn == 1: + type = "string" + self.tokens.append(Token(lexeme.value, type, status, lexeme.line)) + + return self.tokens diff --git a/src/greenberry/gbtools/parser.py b/src/greenberry/gbtools/parser.py new file mode 100644 index 0000000..e69de29 diff --git a/src/greenberry/greenberry_lex_test.py b/src/greenberry/greenberry_lex_test.py new file mode 100644 index 0000000..8fd10f9 --- /dev/null +++ b/src/greenberry/greenberry_lex_test.py @@ -0,0 +1,73 @@ +import inspect + +from debug_cp import * +from gb_utils.greenberry_lex import GreenBerryLex +from symbols import * + +MATH_OPS = ["+", "-", "*", "/"] +BOOLS = [S.TRUE, S.FALSE] +BOOL_OPS = [S.GREATER, S.LESS] +EOS = [S.NL, S.EOF] + + +def greenberry_lex_test(x, expected): + KWDs = [ + getattr(S, i) + for i in [ + b[0] + for b in [ + a + for a in inspect.getmembers(S, lambda a: not inspect.isroutine(a)) + if not (a[0].startswith("__") and a[0].endswith("__")) + ] + ] + ] + words = GreenBerryLex.lex(x, KWDs, add_eof=1) + print("\033[1mWords:\033[0m") + is_correct = True + j = 0 + for i in words: + print(i) + if not i == expected[j]: + print("\x1b[31m This token is unexpected.\x1b[39m") + is_correct = False + j += 1 + return is_correct + + +def greenberry_lex_tester(to_lex, *args): + l_args = list(args) + l_args.append("{***end-of-file***}") + result = greenberry_lex_test(to_lex, l_args) + if result: + print("\x1b[32m Test passed \x1b[39m") + else: + print("\x1b[31m Test failed \x1b[39m") + return result + + +def greenberry_multi_tests(*args): + result = True + for i in args: + cur = greenberry_lex_tester(i["test"], *i["expected"]) + if not cur: + result = False + if result: + print("\x1b[32m All tests passed. \x1b[39m") + else: + print("\x1b[31m A test failed. \x1b[39m") + + +greenberry_multi_tests( + {"test": 'print "hi"', "expected": ["print", '"hi"']}, + {"test": "print string hi", "expected": ["print", "string", "hi"]}, + { + "test": "5 * 3 + (3 / 1)", + "expected": ["5", "*", "3", "+", "(", "3", "/", "1", ")"], + }, + { + "test": "for 3 times: print greenBerry", + "expected": ["for", "3", "times", ":", "print", "greenBerry"], + }, + {"test": "var y = @ x", "expected": ["var", "y", "=", "@", "x"]}, +) diff --git a/src/greenberry/main.gb b/src/greenberry/main.gb new file mode 100644 index 0000000..bde752f --- /dev/null +++ b/src/greenberry/main.gb @@ -0,0 +1,41 @@ + +var x = 1 +var y = string abcd + +print eval (2+3-4+11) +print a +print @x +print @y +print string Hello world! + +if arj = greenBerry : print ok +if 3 > 2 : print apple +if 2 > 3 : print orange +if 1 <= 3: print banana +if 2 >= 5: print grape +if @y = abcd : print pear +if @y = ab : print 6 + +for 5 times : print greenBerry + +set debug on + +class Man : power = 10 action walk : print walking... + +make Man walk +see power Man + +add Man attribute name = string i am me +add Man action run : print running... + +var x = [3,2,3,4,3] +print @x +print @x[0] + +func vector: print string vector is fun +func p x y: print @x + +call vector +call p hello hi + +plot 1-2.5-6 time[s], 'y.txt' path[m] diff --git a/src/greenberry/math.py b/src/greenberry/math.py new file mode 100644 index 0000000..ea1fee1 --- /dev/null +++ b/src/greenberry/math.py @@ -0,0 +1,24 @@ +""" +Created on Mon Apr 9 11:02:15 2018 + +@author: KraftyCoder +Notes : All Rights Reserved +see theory_notes_simple.py in folder 'greenberry' +""" + +L_User = "dear berry" + + +class M: # math + ODD = "odd" + EVEN = "even" + PRIME = "prime" + PI = "pi" + LOG = "log" + LOG10 = "log10" # log(x) returns the logarithm value of x + SQROOT = "sqroot" # sqroot(x) should return square root value of x + SQ = "square" # square(x) returns square value of x + TAN = "tan" # tan(x) returns tangent value of x + COS = "cos" # cos(x) returns cosine value of x + SIN = "sin" # sin(x) returns sine value of x + HYP = "hyp" # returns sqroot(x**2 + y**2), takes in two parameters diff --git a/src/greenberry/symbols.py b/src/greenberry/symbols.py new file mode 100644 index 0000000..a373fd6 --- /dev/null +++ b/src/greenberry/symbols.py @@ -0,0 +1,109 @@ +L_user = "dear berry" + + +class S: + """ + contains symbols used in lang + """ + + EOF = "{***end-of-file***}" + NL = "\n" + WS = " " + E = "" + + EQUAL = "=" + LESS = "<" + GREATER = ">" + EQUAL_GREATER = ">=" + EQUAL_LESS = "<=" + COMMA = "," + SQL = "[" + SQR = "]" + + PRINT = "print" + + NUMBER = "number" + STRING = "string" + BOOL = "bool" + + TRUE = "true" + FALSE = "false" + + EVAL = "eval" + + VAR = "var" + VAR_REF = "@" + PLOT = "plot" + FOR = "for" + IF = "if" + COLON = ":" + FUNCDEF = "func" + FUNCCALL = "call" + CLASS = "class" + ACTION = "action" + COMMA = "," + IS = "is" + MAKE = "make" + ADD = "add" + SEE = "see" + SET = "set" + ATTRIB = "attribute" + TABLE = "table" + + +class T: + """ + type of symbols + """ + + ES = "ending statement" + BO = "bool operator" + EO = "equal operator" + VI = "var type identifier" + VD = "values delimiter" + AS = "array symbol" + + +class E: + global L_user + """ + contains error messages + """ + beg = "" + FOR = beg + L_user + " you made a mistake on a for loop on line" + IF = beg + L_user + " you made a mistake on an if statement on line" + FUNCDEF = beg + L_user + " you ill defined a function on line" + FUNCCALL = beg + L_user + " you wrongly called a function on line" + CLASSNAME = beg + L_user + " you pointed to an inexistent class" + CLASSDEC = beg + L_user + " you wrongly declared a class on line" + CLASSACT = beg + L_user + " you wrongly called an action on line" + CLASSATT = beg + L_user + " you wrongly specified an attribute on line" + PRINT = beg + L_user + " you wrongly used print on line" + VARREF = beg + L_user + " you wrongly referenced a variable on line" + EVAL = beg + L_user + " you wrongly used eval on line" + STRING = beg + L_user + " you used string wrongly on line" + PLOT = beg + L_user + " you plotted wrongly on line" + DEBUG = beg + L_user + " wrong set command on line" + EQUAL = beg + L_user + " expecting = on line" + COLON = beg + L_user + " expected : on line" + ADD = beg + L_user + " wrong add statement" + + +class M: # memory + """ + global memory + """ + + g_vars = {} + g_fs = {} + g_cls = {} + + +class F: + """ + flags + """ + + bStart = 100 # block start + bEnd = 0 + isDebugOn = 0 diff --git a/src/greenberry/test.gb b/src/greenberry/test.gb new file mode 100644 index 0000000..66aaea6 --- /dev/null +++ b/src/greenberry/test.gb @@ -0,0 +1,19 @@ +var x = 1 +var y = string squashed berry 3 +var y = juice +var y = @ x +var z = bool true +var z = bool 1 +var z = bool false +var z = bool 0 +var num_arr = [1, 54, 54, 543, 5345, 35435, 36565] +print @ x +print @ num_arr +print @ num_arr[3] +class Man:power = 10 action walk: print walking... +make Man walk +add to Man attribute me = string i am me +add to Man action run: print running... +func vector: print string vector is fun +func p x: print @ x +call vector diff --git a/src/greenberry/theory_notes_simple.py b/src/greenberry/theory_notes_simple.py new file mode 100644 index 0000000..c75eadc --- /dev/null +++ b/src/greenberry/theory_notes_simple.py @@ -0,0 +1,737 @@ +""" +ALL RIGHTS RESERVED ABDUR_RAHMAAN JANHANGEER +_______________________________________________________________________________ +COMMON COMPILER THEORY SYNTAX P1 + +- eof -> end of file character : tells the lexer that it has encountered the + end of the file. Current methods just return a value telling it has reached + the end +- grammar -> set of rules that describe a language +- context-free grammar -> rules that define a language independent of syntax +- Context-Free Grammar (CFG) in our case -> a set of rules that + describe all possible strings in a given formal language +*** +it is to be noted that source code are of type strings and as such the word +'string' is used +*** + +- production -> production rules specify replacement or substitutions. e.g. + A → a means that A can be replaced by a. A → a is a production +- start symbol -> In the example below, S is the start symbol + S → Av + A → x + +- terminal -> does not appear on the left side of a production +- non-terminal -> that which can be broken down further +*** +terminal symbol is one thing in grammar and another in syntax analysis. +see tokens below +*** +- term -> what you add or substract e.g. 1+2+3 i.e. 1 2 3 +- factor -> what you multiply or divide e.g. 3*4*5 i.e 3 4 5 +- expression -> combination of term and expression etc +______________________________________________________________________ +FORMAL GRAMMAR REPRESENTATIONS + +-- Chomsky Normal Form (CNF) +basically has → and | where it means or +normally starts with S to denote Start symbol +Capital letters means replaceable characters + +S -> a +#meaning only possible sentence is the token a + +S -> aBa +B -> bb +#B can be replaced with bb + +USE OF | + +S -> aBa +B -> bb +B -> aa + +can be represented by + +S -> aBa +B -> bb | aa + +(| means or thus meaning two choices) + +the above define strings of fixed length. not useful for programming languages +to solve this we use recursion. see + +S -> aBa +B -> bb | aaB + +more or less complete description of a computer lang : + +S -> EXPRESSION +EXPRESSION -> TERM | TERM + EXPRESSION | TERM - EXPRESSION +TERM -> FACTOR | FACTOR * EXPRESSION | FACTOR / EXPRESSION +FACTOR -> NUMBER | ( EXPRESSION ) +NUMBER -> 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | + 1 NUMBER | 2 NUMBER | 3 NUMBER | 4 NUMBER | + 5 NUMBER | 6 NUMBER | 7 NUMBER | 8 NUMBER | + 9 NUMBER | 0 NUMBER + +-- Extended Backus Naur Form (EBNF) +Backus and Naur worked on a representation scheme and others extended on it + +uses :== as separator +terminals in '' +[] 0 or 1 occurance of expansion +{} 1 or >1 occurance of expansion + +S :== 'a' B 'a' +B :== 'bb' + +grammar example +S :== EXPRESSION +EXPRESSION :== TERM | TERM { [+,-] TERM] } +TERM :== FACTOR | FACTOR { [*,/] FACTOR] } +FACTOR :== NUMBER | '(' EXPRESSION ')' +NUMBER :== '1' | '2' | '3' | '4' | '5' | + '6' | '7' | '8' | '9' | '0' | + '1' NUMBER | '2' NUMBER | '3' NUMBER | + '4' NUMBER | '5' NUMBER | '6' NUMBER | + '7' NUMBER | '8' NUMBER | '9' NUMBER | '0' NUMBER + + +______________________________________________________________________ +GRAMMAR.TXT + +in many languages you have a file defining the grammar in a file called +grammar.txt (which greenBerry's author has not yet included upto now). + +1) C lang : see end of file + +2) +Here is a more common example : + +program = stmts eof "program1" ; + +stmts = stmt "stmts1" (';' stmt "stmts2")* ; + +stmt = "stmt1" + | selection "stmt2" + | iteration "stmt3" + | assignment "stmt4" ; + +selection = 'if' alts 'fi' "selection1" ; + +iteration = 'do' alts 'od' "iteration1" ; + +alts = alt "alts1" ('::' alt "alts2")* ; + +alt = guard '?' stmts "alt1" ; + +guard = expr "guard1" ; + +assignment = vars ':=' exprs "assignment1" + | vars ':=' subprogram ':=' exprs "assignment2" + | ':=' subprogram ':=' exprs "assignment3" + | vars ':=' subprogram ':=' "assignment4" + | ':=' subprogram ':=' "assignment5" ; + +vars = id "vars1" (',' id "vars2")* ; + +exprs = expr "exprs1" (',' expr "exprs2")* ; + +subprogram = id "subprogram1" ; + +expr = disjunction "expr1" ; + +disjunction = conjunction "disjunction1" ('|' conjunction "disjunction2")* ; + +conjunction = negation "conjunction1" ('&' negation "conjunction2")* ; + +negation = relation "negation1" + | '~' relation "negation2" ; + +relation = sum "relation1" + | sum '<' sum "relation2" + | sum '<=' sum "relation3" + | sum '=' sum "relation4" + | sum '~=' sum "relation5" + | sum '>=' sum "relation6" + | sum '>' sum "relation7" ; + +sum = (term "sum1" | '-' term "sum2") ('+' term "sum3" | '-' term "sum4")* ; + +term = factor "term1" + ('*' factor "term2" | '/' factor "term3" | '//' factor "term4")* ; + +factor = 'true' "factor1" + | 'false' "factor2" + | integer "factor3" + | real "factor4" + | id "factor5" + | '(' expr ')' "factor6" + | 'b2i' factor "factor7" + | 'i2r' factor "factor8" + | 'r2i' factor "factor9" + | 'rand' "factor10" ; + +3) +another variety + +program ::= func | e +func ::= DEFINE type id ( decls ) block program +block ::= BEGIN decls stmts END program +decls ::= decls decl | e +decl ::= type id; +type ::= type [ num ] | basic +stmts ::= stmts stmt | e +stmt ::= id = bool; + | decls + | IF ( bool ) stmt | IF ( bool ) stmt ELSE stmt + | WHILE ( bool ) stmt | DO stmt WHILE ( bool ); + | BREAK; + | PRINT lit; + | READ id; + | block + | RETURN bool; +bool ::= bool OR join | join +join ::= join AND equality | equality +equality ::= equality == rel | equality != rel | rel +rel ::= expr < expr | expr <= expr | expr >= expr | + expr > expr | expr +expr ::= expr + term | expr - term | term +term ::= term * unary | term / unary | unary +unary ::= NOT unary | - unary | factor +factor ::= ( bool ) | id | num | real | true | false + + +____________________________________________________________________________ +COMMON COMPILER THEORY SYNTAX P2 +- identifiers(id) -> must be declared before they are used +- litteral -> fixed values : 11, 'w' +- constants -> change-once values : once declared / set cannot be altered +- variables -> multiple changes allowed + +- CBC lexer -> CBC means Char/character by Char/character, a program that goes + over the source text character by character + +- keyword -> word having a special meaning to the compiler + +- lexeme -> set of characters identified by the lexer + e.g x = 5 + pencils + lexemes : x,=,5,+,pencils + +- pattern -> set of rules that specifies when the sequence of characters from + an input makes a token + +- token -> typically a mapping of value and type. common cases : + 1) identifiers + 2) keywords + 3) operators + 4) special symbols + 5) constant e.g. PI + + for more info see STEP 1 in analysis + token and terminal symbol are in essence the same + +- front-end : from high-level language to some intermediate language +- back-end : from some intermediary language to binary code + in each steps below, front-end and back-end has been labelled in () +__________ __ __ +CASE : +x = 1 + y * 5 + +symbol table : contains symbol, type and scope (psst + - * don't have scope, + referring to id) + +_______________________________________________________________________________ +ANALYSIS +_________ +(front-end) +STEP 1 : Lexical Analysis -> output tokens +info : tool known as Lexer or Scanner + +x -> identifier (id) += -> assignment operator +1 + y -> expression + 1 -> litteral, type : number + + -> add operator + y -> identifier (id) +* -> mult operator +5 -> litteral, type : number + +transformed into tokens where + means first id +<=> for eqal sign as it is a litteral : +tokens : + <=> <+> <*> + +starting here and in subsequent steps, symbol table : + 1. x + 2. y + +Normally : Skips whitespace (new line, space, tabs ...), +ignore comments (single line, multiline) +_________ +(front-end) +STEP 2 : Syntax analysis -> checks order of tokens +info : tool known as Parser + + <=> (verified) + <=> <*> (unverified) + +also generates parse trees + ASSIGN + | + id = expression + | | + x expression + expression + | | + number expression * expression + 1 | | + identifier number + y 5 + syntax tree as + + = + + + * + + +trees are often generated in JSON format or XML format + +JSON +{ + 'some_id': + { + 'type':...., + 'another_property':...., + 'etc':...., + } +} + +XML + + func + + +etc ... just a good enough to represent and handle format +_________ +(front-end) +STEP 3 : Semantical Analysis (semantics means meaning) +generates extended syntax tree +handles type corecion for the parse tree above (given y was float) + = + + + * + int_to_float + +_______________________________________________________________________________ +SYNTHESIS + +_________ +(front-end) +STEP 1: intermediate code generation +the farthest nodes are reduced like +t1 = tofloat(5) +t2 = t1 * id_2 +t3 = 1 + t2 +id_1 = t3 + +_________ +(front-end) +STEP 2: optimisation +t1 = 5.0 * id_2 +id_1 = 1 + t1 + +high-level to high-level stops here + +_________ +(back-end) +STEP 3: code generation +the above in assembly or VM (Virtual Machine) code (psst worth a try) + +_________ +(back-end) +STEP 4: target specific optimisation + +Bibliography : + - wikipaedia.com + - dragon book + - tiger book + - mdh.se lectures 07/04, compiler-intro + - Compiler Basics, James Alan Farrell (1995) + - Vipul97 on github + - OrangeAaron on github + - Elements of Computing Systems, MIT Press, Nisan & Schocken + - Basics of Compiler Design, Torben Ægidius Mogensen + - stackoverflow.com + - tutorialspoint.com + - dartmouth.edu, Bill McKeeman (2007) + +useful demos : + http://effbot.org/zone/simple-top-down-parsing.htm +""" + +if __name__ == "__main__": + print("see infile notes") + +""" +Here is a grammar.txt for the C lanaguage, which reveals quite a few +tricks you might not know about + +primary-expression + identifier + constant + string-literal + ( expression ) + +postfix-expression + primary-expression + postfix-expression [ expression ] + postfix-expression ( ) + postfix-expression ( argument-expression-list ) + postfix-expression . identifier + postfix-expression -> identifier + postfix-expression ++ + postfix-expression -- + +argument-expression-list + assignment-expression + argument-expression-list , assignment-expression + +unary-expression + postfix-expression + ++ unary-expression + -- unary-expression + unary-operator cast-expression + sizeof unary-expression + sizeof ( type-name ) + +unary-operator + & + * + + + - + ~ + ! + +cast-expression + unary-expression + ( type-name ) cast-expression + +multiplicative-expression + cast-expression + multiplicative-expression * cast-expression + multiplicative-expression / cast-expression + multiplicative-expression % cast-expression + +additive-expression + multiplicative-expression + additive-expression + multiplicative-expression + additive-expression - multiplicative-expression + +shift-expression + additive-expression + shift-expression << additive-expression + shift-expression >> additive-expression + +relational-expression + shift-expression + relational-expression < shift-expression + relational-expression > shift-expression + relational-expression <= shift-expression + relational-expression >= shift-expression + +equality-expression + relational-expression + equality-expression == relational-expression + equality-expression != relational-expression + +AND-expression + equality-expression + AND-expression & equality-expression + +exclusive-OR-expression + AND-expression + exclusive-OR-expression ^ AND-expression + +inclusive-OR-expression + exclusive-OR-expression + inclusive-OR-expression | exclusive-OR-expression + +logical-AND-expression + inclusive-OR-expression + logical-AND-expression && inclusive-OR-expression + +logical-OR-expression + logical-AND-expression + logical-OR-expression || logical-AND-expression + +conditional-expression + logical-OR-expression + logical-OR-expression ? expression : conditional-expression + +assignment-expression + conditional-expression + unary-expression assignment-operator assignment-expression + +assignment-operator + = + *= + /= + %= + += + -= + <<= + >>= + &= + ^= + |= + +expression + assignment-expression + expression , assignment-expression + +constant-expression + conditional-expression + +# +# C declaration rules +# + +declaration + declaration-specifiers ; + declaration-specifiers init-declarator-list ; + +declaration-specifiers + storage-class-specifier + type-specifier + type-qualifier + storage-class-specifier declaration-specifiers + type-specifier declaration-specifiers + type-qualifier declaration-specifiers + +init-declarator-list + init-declarator + init-declarator-list , init-declarator + +init-declarator + declarator + declarator = initializer + +storage-class-specifier + typedef + extern + static + auto + register + +type-specifier + void + char + short + int + long + float + double + signed + unsigned + struct-or-union-specifier + enum-specifier + typedef-name + +struct-or-union-specifier + struct-or-union { struct-declaration-list } + struct-or-union identifier { struct-declaration-list } + struct-or-union identifier + +struct-or-union + struct + union + +struct-declaration-list + struct-declaration + struct-declaration-list struct-declaration + +struct-declaration + specifier-qualifier-list struct-declarator-list ; + +specifier-qualifier-list + type-specifier + type-qualifier + type-specifier specifier-qualifier-list + type-qualifier specifier-qualifier-list + +struct-declarator-list + struct-declarator + struct-declarator-list , struct-declarator + +struct-declarator + declarator + constant-expression + declarator constant-expression + +enum-specifier + enum { enumerator-list } + enum identifier { enumerator-list } + enum identifier + +enumerator-list + enumerator + enumerator-list , enumerator + +enumerator + enumeration-constant + enumeration-constant = constant-expression + +enumeration-constant + identifier + +type-qualifier + const + volatile + +declarator + direct-declarator + pointer direct-declarator + +direct-declarator + identifier + ( declarator ) + direct-declarator [ ] + direct-declarator [ constant-expression ] + direct-declarator ( ) + direct-declarator ( parameter-type-list ) + direct-declarator ( identifier-list ) + +pointer + * + * pointer + * type-qualifier-list + * type-qualifier-list pointer + +type-qualifier-list + type-qualifier + type-qualifier-list type-qualifier + +parameter-type-list + parameter-list + parameter-list , ... + +parameter-list + parameter-declaration + parameter-list , parameter-declaration + +parameter-declaration + declaration-specifiers declarator + declaration-specifiers + declaration-specifiers abstract-declarator + +identifier-list + identifier + identifier-list , identifier + +type-name + specifier-qualifier-list + specifier-qualifier-list abstract-declarator + +abstract-declarator + pointer + direct-abstract-declarator + pointer direct-abstract-declarator + +direct-abstract-declarator + ( abstract-declarator ) + [ ] + [ constant-expression ] + ( ) + ( parameter-type-list ) + direct-abstract-declarator [ ] + direct-abstract-declarator [ constant-expression ] + direct-abstract-declarator ( ) + direct-abstract-declarator ( parameter-type-list ) + +typedef-name + identifier + +initializer + assignment-expression + { initializer-list } + { initializer-list , } + +initializer-list + initializer + initializer-list , initializer + +# +# C statement rules +# + +statement + labeled-statement + compound-statement + expression-statement + selection-statement + iteration-statement + jump-statement + +labeled-statement + identifier : statement + case constant-expression : statement + default : statement + +compound-statement + { } + { declaration-list } + { statement-list } + { declaration-list statement-list } + +declaration-list + declaration + declaration-list declaration + +statement-list + statement + statement-list statement + +expression-statement + ; + expression ; + +selection-statement + if ( expression ) statement + if ( expression ) statement else statement + switch ( expression ) statement + +iteration-statement + while ( expression ) statement + do statement while ( expression ) ; + for ( ; ; ) statement + for ( ; ; expression ) statement + for ( ; expression ; ) statement + for ( ; expression ; expression ) statement + for ( expression ; ; ) statement + for ( expression ; ; expression ) statement + for ( expression ; expression ; ) statement + for ( expression ; expression ; expression ) statement + +jump-statement + goto identifier ; + continue ; + break ; + return ; + return expression ; + +translation-unit + external-declaration + translation-unit external-declaration + +external-declaration + function-definition + declaration + +function-definition + declarator compound-statement + declaration-specifiers declarator compound-statement + declarator declaration-list compound-statement + declaration-specifiers declarator declaration-list compound-statement +""" diff --git a/src/greenberry/utils.py b/src/greenberry/utils.py new file mode 100644 index 0000000..dd74fe2 --- /dev/null +++ b/src/greenberry/utils.py @@ -0,0 +1,116 @@ +import contextlib +from io import StringIO + +from greenberry.gb import greenBerry_eval + + +def eval(str): + """ + Function to evaluate postfix expression + """ + + exp = list(str) + S = [] + i = 0 + while i < len(exp): + if exp[i].isnumeric(): + S.append(exp[i]) + else: + y = int(S[-1]) + S.pop() + x = int(S[-1]) + S.pop() + if exp[i] == "+": + S.append(x + y) + elif exp[i] == "-": + S.append(x - y) + elif exp[i] == "*": + S.append(x * y) + elif exp[i] == "/": + S.append(x // y) + elif exp[i] == "^": + S.append(x**y) + else: + pass + i = i + 1 + print(S[0]) + + +def maths_eval(string): # previous InfixCon + """ + Converts Infix expression to postfix + Enter the expression to evaluate but mind the brackets in case of multiply and divide + """ + res = "" + exp = string + exp = list(exp) + S = [] + L = [] + i = 0 + while i < len(exp): + if exp[i] >= "0" and exp[i] <= "9": + res = res + exp[i] + + else: + if len(S) == 0 or exp[i] == "(" or exp[i] == "^": + S.append(exp[i]) + elif exp[i] == ")": + while S[-1] != "(": + res = res + S[-1] + S.pop() + S.pop() + elif exp[i] == "*" or exp[i] == "/": + if S[-1] == "^": + while len(S) > 0 and S[-1] != "(": + res = res + S[-1] + S.pop() + S.append(exp[i]) + elif S[-1] == "*" or S[-1] == "/": + while len(S) > 0 and S[-1] != "(" and S[-1] != "^": + res = res + S[-1] + S.pop() + S.append(exp[i]) + else: + S.append(exp[i]) + elif exp[i] == "+" or exp[i] == "-": + if S[-1] == "^" or S[-1] == "*" or S[-1] == "/": + while len(S) > 0 and S[-1] != "(": + res = res + S[-1] + S.pop() + S.append(exp[i]) + elif S[-1] == "+" or S[-1] == "-": + while ( + len(S) > 0 + and S[-1] != "(" + and S[-1] != "^" + and S[-1] != "*" + and S[-1] != "/" + ): + res = res + S[-1] + S.pop() + S.append(exp[i]) + else: + S.append(exp[i]) + i = i + 1 + while len(S) > 0: + res = res + S[-1] + S.pop() + eval(res) + + +def capture_gb_eval_print(code): + temp_stdout = StringIO() + # redirect stdout to catch print statement from eval function + with contextlib.redirect_stdout(temp_stdout): + greenBerry_eval(code) + output = temp_stdout.getvalue().strip() + return output + + +def capture_maths_eval_print(code): + temp_stdout = StringIO() + # redirect stdout to catch print statement from eval function + with contextlib.redirect_stdout(temp_stdout): + maths_eval(code) + output = temp_stdout.getvalue().strip() + return output diff --git a/src/greenberry/x.txt b/src/greenberry/x.txt new file mode 100644 index 0000000..e65cb1d --- /dev/null +++ b/src/greenberry/x.txt @@ -0,0 +1 @@ +1.33-5-10.8 diff --git a/src/greenberry/y.txt b/src/greenberry/y.txt new file mode 100644 index 0000000..a2ae718 --- /dev/null +++ b/src/greenberry/y.txt @@ -0,0 +1 @@ +30-60-75.7575