I am building a mini-coding language and I have run into an error. So I have this function lex() that checks what the current char is and appends it to tokens. So if char=1, then it would append NUM:1 to tokens. So I have lex() check for LPAREN and RPAREN, but the problem is, RPAREN gets appended 1 time too early. for example: is i enter 2*(2*2), the tokens array would be: ['NUM:2', 'OP:*', 'LPAREN(', 'NUM:2', 'OP:*', 'RPAREN)', 'NUM:2']. I need this to be fixed.
Code:
funCall = False
operators = ['+', '-', '*', '/']
# Lexer
def lex(line):
idx = 0
line = line.replace(" ", "")
num = ""
tok = ""
isNum = False
funCall = False
tokens = []
for char in line:
if char.isdigit():
isNum = True
num+=char
elif char in operators:
if isNum:
tokens.append(f"NUM:{num}")
num=""
isNum = False
tokens.append(f"OP:{char}")
elif char == "(" or char == ")":
if not funCall:
if char=="(":
tokens.append(f"LPAREN{char}")
elif char==")":
tokens.append(f"RPAREN{char}")
if isNum:
tokens.append(f"NUM:{num}")
return tokens
# Parser
#TODO: Append add all variables to variables.py, then whenever out.py would be reset, add variables.py to it
def parse(tokens):
equation = ""
if not tokens:
return "Syntax error"
print(tokens)
for tok in tokens:
if "NUM" in tok:
equation+=tok[4:]
elif "OP" in tok:
equation+=tok[3:]
elif "LPAREN" in tok:
equation+="("
elif "RPAREN" in tok:
equation+=")"
# try:
out = open("out.py","a")
out.write(equation)
out.write("\n")
out.flush()
os.fsync(out.fileno())
out.close()
return eval(equation)
# except:
# return f"Invalid equation {equation}"
while True:
data = input("KPP>")
print(parse(lex(data)))
Related
I am currently creating a mini-programming language for beginners. I am right now at the process of parsing a function call. So what will happen when the user enters the line: show(1), I call eval() on that function(it is built in so it is already defined). And that works and print 1. But then when the user enters a=2(that will enter the name and value into the dictionary variables. After the user enters that line, and then enters show(a), i run into the error "name 'a' is not defined from the eval() function. So what i need to do is allow the user to enter a variable into the function call and it will parse it. If I have to I can stop using eval() and use some better method but what I researched showed eval.
Python3 code:
def show(arg):
print(arg)
import os
funCall = False
# Open the file that we will write all of the lines of code to
out = open("out.py","w")
# Open the file with all of the built in functions
functions = open("functions.py","r").read()
# Add built in functions to out so that the user can use them
out.write(functions)
out.write("\n")
out.flush()
os.fsync(out.fileno())
operators = ['+', '-', '*', '/']
var_assign = '='
variables = {}
varArray = []
# Lexer
def lex(line):
idx = 0
line = line.replace(" ", "")
num = ""
tok = ""
isNum = False
funCall = False
tokens = []
for char in line:
if char.isdigit():
isNum = True
num+=char
elif char in operators:
if isNum:
tokens.append(f"NUM:{num}")
num=""
isNum = False
tokens.append(f"OP:{char}")
elif char == "=":
try:
if line[:idx].isdigit():
return None
else:
tokens.append(f"VAR_ASSIGN:{line[:idx]}={line[idx+1:]}")
except:
return ""
elif char.isalpha() and "(" in line and ")" in line:
if '-' not in line and '+' not in line and '*' not in line and '/' not in line:
if line[:line.index('(')].isalpha():
if funCall:
continue
tokens.append(f"FUNC_CALL{line}")
funCall = True
elif char.isalpha() and "=" not in line:
try:
if '-' in line or '+' in line or '*' in line or '/' in line:
if "(" not in line and ")" not in line and "{" not in line and "}" not in line:
tokens.append(f"VAR_USE:{char}")
else:
tokens.append(f"VAR_CALL:{line}")
except:
return ""
idx+=1
if isNum:
tokens.append(f"NUM:{num}")
return tokens
# Parser
def parse(tokens):
equation = ""
if not tokens:
return "Syntax error"
for tok in tokens:
if "NUM" in tok:
equation+=tok[4:]
elif "OP" in tok:
equation+=tok[3:]
elif "VAR_ASSIGN" in tok:
tok = tok[11:]
variables[tok[:tok.index('=')]] = tok[tok.index('=')+1:]
varArray.append(tok[:tok.index('=')])
out.write(str(tok[:tok.index('=')]) + str('=') + str(tok[tok.index('=')+1:]))
out.write("\n")
out.flush()
os.fsync(out.fileno())
return variables[tok[:tok.index('=')]]
elif "FUNC_CALL" in tok:
# out.write(tok[9:])
# out.write("\n")
# out.flush()
# os.fsync(out.fileno())
funcName = tok[9:]
try:
eval(funcName)
except:
return f"Error in the calling of function: {tok[9:]}"
return "Success"
elif "VAR_CALL" in tok:
try:
return variables[tok[9:]]
except:
return "Variable not defined"
elif "VAR_USE" in tok:
try:
equation += variables[tok[8:]]
except:
return "Variable not defined"
try:
out.write(equation)
out.write("\n")
out.flush()
os.fsync(out.fileno())
return eval(equation)
except:
return f"Invalid equation {equation}"
while True:
data = input("KPP>")
print(parse(lex(data)))
I don't know what to add. At the time that's why I only posted the code.
But the intended result is that a string should be parsed (and successfully printed).
I don't remember what the issue was, but by the sounds of it, it probably just didn't print.
(I'm doing this to get back on S.O.'s "good side".)
class Lex:
def run(args, string):
if args == "print":
print(str(string))
class Calin:
string = ""
running = ""
def parse(args):
lexic = Lex
string = ""
tok = ""
state = 0
for char in args:
tok += char
if tok == " ":
if state == 0:
tok = ""
elif state == 1:
tok = " "
elif tok == "\"":
if state == 0:
state = 1
elif state == 1:
state = 0
elif state == 1:
string += char
elif tok == "print":
running = "print"
lexic.run(running, string)
trans = Calin
trans.parse("print \"WOW A STRING\"")
Because you are making state == 1 only when tok == "\"", which never happens (You are keep adding strs to it.). Changing it to char works:
class Lex:
def run(args, string):
if args == "print":
print(str(string))
class Calin:
string = ""
running = ""
def parse(args):
lexic = Lex
string = ""
tok = ""
state = 0
for char in args:
tok += char
if tok == " ":
if state == 0:
tok = ""
elif state == 1:
tok = " "
elif char == "\"": # <<< Change this
if state == 0:
state = 1
elif state == 1:
state = 0
elif state == 1:
string += char
elif tok == "print":
running = "print"
lexic.run(running, string)
trans = Calin
trans.parse("print \"WOW A STRING\"")
# WOW A STRING
I'm writing a program to take a user input of parentheses i.e. {} [] () and checking to see if they have a pair (opening and closing). I'm running into an error when running my code where i always get the return false. I've tried different ways of checking against a pre set "list" but it doesn't seem to work. I have to use the class from above too. any help is appreciated.
some example inputs are:
>>>parenthesesMatch('{[]}')
True
>>>parenthesesMatch('({})')
True
>>>parenthesesMatch('{[)]}')
False
My code:
#George flamburis
class Stack():
def __init__(self,que=[]):
self.lst = que
def __repr__(self):
return "Stack({})".format(self.lst)
def push(self, add):
self.lst.append(add)
def pop(self):
return self.lst.pop()
def isEmpty(self):
return self.lst==[]
def first(self, loc=0): #naming of this method can't be []
return self.lst[loc]
def len(self):
return len(self.lst)
def parenthesesMatch(match):
s = Stack()
end = []
for char in match:
if char in "[ { (":
s.push(char)
else:
end.append(char)
if s.len()==len(end):
for num in range(len(end)):
if s.first(num) and end[num] not in '[]' or '{}' or'()':
return False
return True
elif s.len()!=len(end):
return False
It's much easier to simply attempt to pop a closing character off the stack when you see one, and fail if that isn't possible.
pairs = dict(tuple(pair) for pair in ["()", "[]", "{}"])
# pairs["("] == ")"
# pairs["["] == "]"
# etc
def parenthesesMatch(match):
s = Stack()
for char in match:
# Not "] } )"
if char in pairs.values() and pairs[s.pop()] != char:
return False
elif char in pairs:
s.push(char)
return s.isEmpty()
def match(par):
combs = {'{': '}', '(': ')', '[': ']'}
stack = []
for char in par:
if char in '[{(':
stack.append(char)
elif char == combs[stack[len(stack) - 1]]:
stack.pop()
else:
return False
return len(stack) == 0
Comments outline my thought.
def isParenthesesMatch(s):
# to be balanced should be divisable by 2
if len(s)%2 != 0:
return False
open_paren = ['(','[','{']
open_paren_stack = list()
match_close_paren = {')' : '(',']': '[', '}' : '{'}
for item in s:
#Don't care about open
if item in open_paren:
open_paren_stack.append(item)
#if closed we should be able to pop
elif len(open_paren_stack) == 0:
return False
#if we can pop it should match up
elif open_paren_stack.pop() != match_close_paren[item]:
return False
#in case we push a bunch of open and then end with balanced pair
return len(open_paren_stack) == 0
def parenthesesMatch(match):
counter = {'{': 0, '[': 0, '(': 0, '}': 0, ']': 0, ')': 0}
parantheses = '{}[]()'
for character in match:
if character not in parantheses:
continue
counter[character] += 1
return (counter['{'] == counter['}']) and (counter['['] == counter[']']) and (counter['('] == counter[')'])
I am trying to make my own basic programming language. I have the following code in my smrlang.py file
from sys import *
tokens = []
def open_file(filename):
data = open(filename, "r").read()
return data
def smr(filecontents):
tok = ""
state = 0
string = ""
filecontents = list(filecontents)
for char in filecontents:
tok += char
if tok == " ":
if state == 0:
tok = ""
else:
tok = " "
elif tok == "PRINT":
tokens.append("PRINT")
tok = ""
elif tok == "\"":
if state == 0:
state = 1
elif state == 1:
print("STRING")
string = ""
state = 0
elif state == 1:
string += tok
print(tokens)
def run():
data = open_file(argv[1])
smr(data)
run()
And I have this in my one.smr file:
PRINT "HELLO WORLD"
The output should be something like PRINT STRING, but when I use the command python3 smrlang.py one.smr, the output is just PRINT. I am using Python 3
Debugging it in the head, I found the problem:
elif state == 1:
string += tok
You don't reset the token here. It will be aababcabcd instead of abcd and recognizing \ won't work (as it will be aababcabcd\).
This also causes the token to just be everything and it will never print.
Try changing it to:
elif state == 1:
string += tok
tok = ""
Output after fix:
> py -3 temp.py temp.txt
STRING
['PRINT']
This is the basic.py file for a programming language I am making. At the moment it is throwing an error.
from sys import *
tokens = []
def open_file(filename):
data = open(filename, "r").read()
data += "<EOF>"
return data
def lex(filecontents):
tok = ""
state = 0
isexpr = 0
string = ""
expr = ""
n = ""
filecontents = list(filecontents)
for char in filecontents:
tok += char
if tok == " ":
if state == 0:
tok = ""
else:
tok = " "
elif tok == "\n" or tok == "<EOF>":
if expr != "" and isexpr == 1:
#print(expr + "EXPR")
tokens.append("EXPR:" + expr)
expr = ""
elif expr != "" and isexpr == 0:
#print(expr + "NUM")
tokens.append("NUM:" + expr)
expr = ""
tok = ""
elif tok.lower() == "print":
tokens.append("PRINT")
tok = ""
elif tok.isnumeric():
expr += tok
tok = ""
elif tok == "+":
isexpr = 1
expr += tok
tok = ""
elif tok == "\"":
if state == 0:
state = 1
elif state == 1:
tokens.append("STRING:" + string + "\"")
string = ""
state = 0
tok = ""
elif state == 1:
string += tok
tok = ""
print(tokens)
return tokens
def parse(toks):
i = 0
while(i < len(toks)):
if toks[i] + " " + toks[i+1][0:6] == "PRINT STRING" or toks[i] + " " + toks[i+1][0:3] == "PRINT NUM" or toks[i] + " " + toks[i+1][0:4] == "PRINT EXPR":
if toks[i+1][0:6] == "STRING":
print(toks[i+1][7:])
elif toks[i+1][0:3] == "NUM":
print(toks[i+1][4:])
elif toks[i+1][0:4] == "EXPR":
print(toks[i+1][5:])
i+=2
def run():
data = open_file(argv[1])
toks = lex(data)
parse(toks)
run()
here is the test.vil file(my programming language is called villar) that I am passing data through:
STRING "HELLO WORLD"
string "Hey world!"
17 + 3
As a result, I get an IndexError: List index out of range in line 62.
Can you anyone help me help here? I'd love advice on how to improve it to if its allowed here.
You've got the line:
while(i < len(toks)):
in the parse function. However, within this while loop, you access toks[i+1] element, which'll be out of bounds on the final iteration of the while loop (as i == len(toks)-1 and i+1 == len(toks) which is out of bounds and throwing an error). You need to change that above line to:
while(i < len(toks)-1):
so that on the final iteration i == len(toks) - 2 and i+1 == len(toks) - 1 which are both in bounds.