Call a function from string that's arguments included a variable - python

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)))

Related

RPAREN appened before NUM?

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)))

My functions have return statements, so why am I getting this error? TypeError: can only concatenate str (not "NoneType") to str

This method is part of a class that converts inputs from infix to postfix. An example input would be: "11.897/3.4+9.2-0.4*6.9/12.6-16.7="
I have some helper methods below the main method (getPostFix).
I can't understand why the code result += ipop is causing the error. I use the same code snippets later in the code, so maybe I will have to fix those instances as well. I read some other answers in which the answers seemed to ask the OP - "well what if this function returns False?" But which functions and why would they do that?
def getPostFix(self):
result = ""
# stack used to create postfix string
self.stack = MyStack()
input_string = self.getInput()
input_string_split = [x for x in re.split("(\d*\.?\d*)", input_string) if x != '']
for i in input_string_split:
if isOperand(i):
result += i
elif isOperator(i):
while True:
topItem = self.stack.getTop()
if self.stack.size == 0 or topItem == '(':
self.stack.push(i)
break
else:
precedence_i = getPrecedence(i)
precedence_topItem = getPrecedence(topItem)
if precedence_i > precedence_topItem:
self.stack.push(i)
break
else:
ipop = self.stack.pop()
result += ipop
#result += self.stack.pop()
elif i == '(':
self.stack.push(i)
elif i == ')':
ipop = self.stack.pop()
while ipop != '(':
result += ipop
ipop = self.stack.pop()
elif i == '=':
ipop = self.stack.pop()
result += ipop
#result += self.stack.pop()
while not self.stack.size == 0:
ipop = self.stack.pop()
result += ipop
def isOperand(c):
return c >= '0' and c <= '9'
operators = "+-*/^"
def isOperator(c):
return c in operators
def getPrecedence(c):
result = 0
for i in operators:
result += 1
# because + - and */ have the same value
# these if statements will set their value equal to each other
# for, example when I get to -, the result count is 2, but I subtract 1 to get 1
# which is the same result count as +.
if i == c:
if c in '-/':
result -= 1
break
return result
Here is the error code:
Traceback (most recent call last):
File " ", line 9, in <module>
print(calc)
File " ", line 23, in __str__
theCalc += 'Postfix input is: ' + self.getPostFix() + '\n'
File " ", line 71, in getPostFix
result += ipop
TypeError: can only concatenate str (not "NoneType") to str
Because sometimes you're popping at the end of the iterable and it returns None, try replacing all the lines of
result += ipop
with
result += ipop if ipop else "" # Handles None cases and returns empty string.

Python - Only printing 'PRINT'

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']

Need help fixing python error

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.

docstring blocks elif statement

Let me past the exact code I have:
This is the short module
class SentenceSplitter:
def __init__(self, filename=None):
self._raw_text = self.raw_text(filename)
self._sentences = self.to_sentences()
def raw_text(self, filename):
text = ''
with open(filename, 'r') as file:
for line in file.readlines():
line = line.strip()
text += ''.join(line.replace(line, line+' '))
file.close()
text = text.strip() # Deal with the last whitespace
return text
def to_sentences(self):
""" Sentence boundaries occur at '.', '!', '?' except that,
there are some not-sentence boundaries that
may occur before/after the period.
"""
raw_text = self._raw_text
sentences = []
sentence = ''
boundary = None
for char in raw_text:
sentence += ''.join(char)
if char == '!' or char == '?':
sentences.append(sentence)
sentence = ''
""" The sign -> refers to 'followed by' """
elif char == '.':
i = raw_text.index(char) # slicing previous/following characters
boundary = True
if boundary:
sentences.append(sentence)
sentence = ''
return sentences
And the main:
import textchange
ss = textchange.SentenceSplitter(filename='text.txt')
print(ss._sentences)
The docstring after the first if statement
""" The sign -> refers to 'followed by' """
I commented it out and the program runs, else does not.
There is more code in the elif statement but removed it after making sure it still throwing error. Here is the traceback:
Traceback (most recent call last):
File "D:\Programs\Python 3.3.2\Tutorials\46 Simple Python Exercises.py", line 26, in
<module>
import textchange
File "D:\Programs\Python 3.3.2\Tutorials\textchange.py", line 51
elif char == '.':
^
SyntaxError: invalid syntax
Docstrings are just string literals that are found at the start of the function. They still have to follow indentation rules.
Your string is not correctly indented for the elif block; by being de-dented from the if block before, you ended the if-elif-else blocks altogether and no elif is permitted to follow.
Use a regular, normal comment instead, a line starting with #; lines that contain only comments are exempt from the indentation rules:
if char == '!' or char == '?':
sentences.append(sentence)
sentence = ''
# The sign -> refers to 'followed by'
elif char == '.':
i = raw_text.index(char) # slicing previous/following characters
boundary = True
or indent the string (which is entirely still executed by Python as code, but otherwise not assigned and thus discarded again):
if char == '!' or char == '?':
sentences.append(sentence)
sentence = ''
elif char == '.':
""" The sign -> refers to 'followed by' """
i = raw_text.index(char) # slicing previous/following characters
boundary = True

Categories

Resources