Skip to content

Instantly share code, notes, and snippets.

@mixstef
Last active May 28, 2021 13:50
Show Gist options
  • Select an option

  • Save mixstef/912d88a89e10babb95f869d62a3e5b3a to your computer and use it in GitHub Desktop.

Select an option

Save mixstef/912d88a89e10babb95f869d62a3e5b3a to your computer and use it in GitHub Desktop.
Ατζέντα εργαστηρίου Μεταγλωττιστών 28/5/2021

Ατζέντα εργαστηρίου Μεταγλωττιστών 28/5/2021

Στο gist αυτό θα αναρτηθούν λύσεις και υποδείξεις κατά τη διεξαγωγή του εργαστηρίου.

# runtime error, a user-defined exception
class RunError(Exception):
pass
class MyParser():
def __init__(self,scanner):
self.symbol_table = {}
self.scanner = scanner
# get initial input token
self.next_token,self.next_lexeme = self.scanner.read()
def Factor(self):
if self.next_token=='(':
# Factor → ( Expr )
self.match('(')
e = self.Expr()
self.match(')')
return e
elif self.next_token=='id':
# Factor → id
varname = self.next_lexeme
self.match('id')
if varname in self.symbol_table:
return self.symbol_table[varname]
raise RunError("Uninitialized variable {}".format(varname))
elif self.next_token=='number':
# Factor → number
value = float(self.next_lexeme)
self.match('number')
return value
else:
raise ParseError("In Factor(), expecting (, id or number, found {} instead".format(self.next_token))
def Stmt(self):
if self.next_token=='id':
# Stmt → id = Expr
varname = self.next_lexeme
self.match('id')
self.match('=')
self.symbol_table[varname] = self.Expr()
elif self.next_token=='print':
# Stmt → print Expr
self.match('print')
print(self.Expr())
else:
raise ParseError("In Stmt(), expecting id or print, found {} instead".format(self.next_token))
def Expr(self):
if self.next_token in ('(','id','number'):
# Expr → Term Term_tail
t = self.Term()
tt = self.Term_tail()
if tt: # tt is (op,t')
if tt[0]=='+':
return t+tt[1]
return t-tt[1]
return t
else:
raise ParseError("In Expr(), expecting (, id or number, found {} instead".format(self.next_token))
def Term(self):
if self.next_token in ('(','id','number'):
# Term → Factor Factor_tail
f = self.Factor()
ft = self.Factor_tail()
if ft: # ft is (op,f')
if ft[0]=='*':
return f*ft[1]
return f/ft[1]
return f
else:
raise ParseError("In Term(), expecting (, id or number, found {} instead".format(self.next_token))
def Factor_tail(self):
if self.next_token in ('*','/'):
# Factor_tail → Multop Factor Factor_tail
op = self.Multop()
f = self.Factor()
ft = self.Factor_tail()
if ft: # ft is (op',f')
if ft[0]=='*':
return op,f*ft[1]
return op,f/ft[1]
return op,f
elif self.next_token in ('+','-','id','print',')',None):
# Factor_tail → e
return
else:
raise ParseError("In Factor_tail(), expecting *, /, +, -, id, print, ) or EOT, found {} instead".format(self.next_token))
def Term_tail(self):
if self.next_token in ('+','-'):
# Term_tail → Addop Term Term_tail
op = self.Addop()
t = self.Term()
tt = self.Term_tail()
if tt: # tt is (op',t')
if tt[0]=='+':
return op,t+tt[1]
return op,t-tt[1]
return op,t
elif self.next_token in ('id','print',')',None):
# Term_tail → e
return
else:
raise ParseError("In Term_tail(), expecting +, -, id, print, ) or EOT , found {} instead".format(self.next_token))
def Addop(self):
if self.next_token=='+':
# Addop → +
self.match('+')
return '+'
elif self.next_token=='-':
# Addop → -
self.match('-')
return '-'
else:
raise ParseError("In Addop(), expecting + or -, found {} instead".format(self.next_token))
def Multop(self):
if self.next_token=='*':
# Multop → *
self.match('*')
return '*'
elif self.next_token=='/':
# Multop → /
self.match('/')
return '/'
else:
raise ParseError("In Multop(), expecting * or /, found {} instead".format(self.next_token))
"""
Recursive descent parser and runner for arithmetic expressions, using plex as scanner.
Grammar is:
Stmt_list → Stmt Stmt_list | ε
Stmt → id = Expr | print Expr
Expr → Term Term_tail
Term_tail → Addop Term Term_tail | ε
Term → Factor Factor_tail
Factor_tail → Multop Factor Factor_tail | ε
Factor → (Expr) | id | number
Addop → + | -
Multop → * | /
"""
import plex
# parsing error, a user-defined exception
class ParseError(Exception):
pass
# runtime error, a user-defined exception
class RunError(Exception):
pass
# class of recursive descent parser
class MyParser():
def __init__(self,scanner):
self.symbol_table = {}
self.scanner = scanner
# get initial input token
self.next_token,self.next_lexeme = self.scanner.read()
def match(self,expected):
if self.next_token==expected:
# proceed to next token
self.next_token,self.next_lexeme = self.scanner.read()
else:
raise ParseError('Expected {}, found {} instead'.format(expected,self.next_token))
def parse(self):
# call method for starting symbol of grammar
self.Stmt_list()
# keep the following to match end-of-text
self.match(None)
def Stmt_list(self):
if self.next_token in ('id','print'):
# Stmt_list → Stmt Stmt_list
self.Stmt()
self.Stmt_list()
elif self.next_token==None:
# Stmt_list → e
return
else:
raise ParseError("In Stmt_list(), expecting id, print or EOT, found {} instead".format(self.next_token))
def Stmt(self):
if self.next_token=='id':
# Stmt → id = Expr
varname = self.next_lexeme
self.match('id')
self.match('=')
self.symbol_table[varname] = self.Expr()
elif self.next_token=='print':
# Stmt → print Expr
self.match('print')
print(self.Expr())
else:
raise ParseError("In Stmt(), expecting id or print, found {} instead".format(self.next_token))
def Expr(self):
if self.next_token in ('(','id','number'):
# Expr → Term Term_tail
t = self.Term()
tt = self.Term_tail()
if tt: # tt is (op,t')
if tt[0]=='+':
return t+tt[1]
return t-tt[1]
return t
else:
raise ParseError("In Expr(), expecting (, id or number, found {} instead".format(self.next_token))
def Term_tail(self):
if self.next_token in ('+','-'):
# Term_tail → Addop Term Term_tail
op = self.Addop()
t = self.Term()
tt = self.Term_tail()
if tt: # tt is (op',t')
if tt[0]=='+':
return op,t+tt[1]
return op,t-tt[1]
return op,t
elif self.next_token in ('id','print',')',None):
# Term_tail → e
return
else:
raise ParseError("In Term_tail(), expecting +, -, id, print, ) or EOT , found {} instead".format(self.next_token))
def Term(self):
if self.next_token in ('(','id','number'):
# Term → Factor Factor_tail
f = self.Factor()
ft = self.Factor_tail()
if ft: # ft is (op,f')
if ft[0]=='*':
return f*ft[1]
return f/ft[1]
return f
else:
raise ParseError("In Term(), expecting (, id or number, found {} instead".format(self.next_token))
def Factor_tail(self):
if self.next_token in ('*','/'):
# Factor_tail → Multop Factor Factor_tail
op = self.Multop()
f = self.Factor()
ft = self.Factor_tail()
if ft: # ft is (op',f')
if ft[0]=='*':
return op,f*ft[1]
return op,f/ft[1]
return op,f
elif self.next_token in ('+','-','id','print',')',None):
# Factor_tail → e
return
else:
raise ParseError("In Factor_tail(), expecting *, /, +, -, id, print, ) or EOT, found {} instead".format(self.next_token))
def Factor(self):
if self.next_token=='(':
# Factor → ( Expr )
self.match('(')
e = self.Expr()
self.match(')')
return e
elif self.next_token=='id':
# Factor → id
varname = self.next_lexeme
self.match('id')
if varname in self.symbol_table:
return self.symbol_table[varname]
raise RunError("Uninitialized variable {}".format(varname))
elif self.next_token=='number':
# Factor → number
value = float(self.next_lexeme)
self.match('number')
return value
else:
raise ParseError("In Factor(), expecting (, id or number, found {} instead".format(self.next_token))
def Addop(self):
if self.next_token=='+':
# Addop → +
self.match('+')
return '+'
elif self.next_token=='-':
# Addop → -
self.match('-')
return '-'
else:
raise ParseError("In Addop(), expecting + or -, found {} instead".format(self.next_token))
def Multop(self):
if self.next_token=='*':
# Multop → *
self.match('*')
return '*'
elif self.next_token=='/':
# Multop → /
self.match('/')
return '/'
else:
raise ParseError("In Multop(), expecting * or /, found {} instead".format(self.next_token))
# main part of program
# pattern definitions
letter = plex.Range("AZaz")
digit = plex.Range("09")
underscore = plex.Str("_")
number = plex.Rep1(digit) + plex.Opt(plex.Str('.') + plex.Rep1(digit))
name = (letter | underscore) + plex.Rep(letter | digit | underscore)
operator = plex.Any('+-*/=()')
k_print = plex.Str('print')
spaces = plex.Rep1(plex.Any(' \t\n'))
# create plex lexicon
lexicon = plex.Lexicon([
(number,'number'),
(operator,plex.TEXT),
(k_print,'print'),
(name,'id'),
(spaces,plex.IGNORE)
])
# open input file for parsing
with open("arithmetic.txt","r") as fp:
# create plex scanner for file fp
scanner = plex.Scanner(lexicon,fp)
# create recursive descent parser
parser = MyParser(scanner)
try:
parser.parse()
except ParseError as e:
_,lineno,charno = scanner.position()
print('Syntax error at line:{} char:{}, {}'.format(lineno,charno+1,e))
except RunError as e:
_,lineno,charno = scanner.position()
print('Runtime error at line:{} char:{}, {}'.format(lineno,charno+1,e))
except plex.errors.PlexError:
_,lineno,charno = scanner.position()
print("Scanner Error at line {} char {}".format(lineno,charno+1))
a = 2 + 7.55*44
print a
b = 3*(a-99.01)
print b*0.23
c = 5-3-2
print c
"""
Recursive descent parser and runner for arithmetic expressions, using plex as scanner.
Grammar is (NOTE: EBNF!):
Stmt_list → Stmt Stmt_list | ε
Stmt → id = Expr | print Expr
Expr → Term (Addop Term)*
Term → Factor (Multop Factor)*
Factor → (Expr) | id | number
Addop → + | -
Multop → * | /
"""
import plex
# parsing error, a user-defined exception
class ParseError(Exception):
pass
# runtime error, a user-defined exception
class RunError(Exception):
pass
# class of recursive descent parser
class MyParser():
def __init__(self,scanner):
self.symbol_table = {}
self.scanner = scanner
# get initial input token
self.next_token,self.next_lexeme = self.scanner.read()
def match(self,expected):
if self.next_token==expected:
# proceed to next token
self.next_token,self.next_lexeme = self.scanner.read()
else:
raise ParseError('Expected {}, found {} instead'.format(expected,self.next_token))
def parse(self):
# call method for starting symbol of grammar
self.Stmt_list()
# keep the following to match end-of-text
self.match(None)
def Stmt_list(self):
if self.next_token in ('id','print'):
# Stmt_list → Stmt Stmt_list
self.Stmt()
self.Stmt_list()
elif self.next_token==None:
# Stmt_list → e
return
else:
raise ParseError("In Stmt_list(), expecting id, print or EOT, found {} instead".format(self.next_token))
def Stmt(self):
if self.next_token=='id':
# Stmt → id = Expr
varname = self.next_lexeme
self.match('id')
self.match('=')
self.symbol_table[varname] = self.Expr()
elif self.next_token=='print':
# Stmt → print Expr
self.match('print')
print(self.Expr())
else:
raise ParseError("In Stmt(), expecting id or print, found {} instead".format(self.next_token))
def Expr(self):
if self.next_token in ('(','id','number'):
# Expr → Term (Addop Term)*
t = self.Term()
while self.next_token in ('+','-'):
op = self.Addop()
t2 = self.Term()
if op=='+':
t += t2
else:
t -= t2
if self.next_token in ('id','print',')',None):
return t
else:
raise ParseError("In Expr(), expecting +, -, id, print, ) or EOT , found {} instead".format(self.next_token))
else:
raise ParseError("In Expr(), expecting (, id or number, found {} instead".format(self.next_token))
def Term(self):
if self.next_token in ('(','id','number'):
# Term → Factor (Multop Factor)*
f = self.Factor()
while self.next_token in ('*','/'):
op = self.Multop()
f2 = self.Factor()
if op=='*':
f *= f2
else:
f /= f2
if self.next_token in ('+','-','id','print',')',None):
return f
else:
raise ParseError("In Term(), expecting *, /, +, -, id, print, ) or EOT, found {} instead".format(self.next_token))
else:
raise ParseError("In Term(), expecting (, id or number, found {} instead".format(self.next_token))
def Factor(self):
if self.next_token=='(':
# Factor → ( Expr )
self.match('(')
e = self.Expr()
self.match(')')
return e
elif self.next_token=='id':
# Factor → id
varname = self.next_lexeme
self.match('id')
if varname in self.symbol_table:
return self.symbol_table[varname]
raise RunError("Uninitialized variable {}".format(varname))
elif self.next_token=='number':
# Factor → number
value = float(self.next_lexeme)
self.match('number')
return value
else:
raise ParseError("In Factor(), expecting (, id or number, found {} instead".format(self.next_token))
def Addop(self):
if self.next_token=='+':
# Addop → +
self.match('+')
return '+'
elif self.next_token=='-':
# Addop → -
self.match('-')
return '-'
else:
raise ParseError("In Addop(), expecting + or -, found {} instead".format(self.next_token))
def Multop(self):
if self.next_token=='*':
# Multop → *
self.match('*')
return '*'
elif self.next_token=='/':
# Multop → /
self.match('/')
return '/'
else:
raise ParseError("In Multop(), expecting * or /, found {} instead".format(self.next_token))
# main part of program
# pattern definitions
letter = plex.Range("AZaz")
digit = plex.Range("09")
underscore = plex.Str("_")
number = plex.Rep1(digit) + plex.Opt(plex.Str('.') + plex.Rep1(digit))
name = (letter | underscore) + plex.Rep(letter | digit | underscore)
operator = plex.Any('+-*/=()')
k_print = plex.Str('print')
spaces = plex.Rep1(plex.Any(' \t\n'))
# create plex lexicon
lexicon = plex.Lexicon([
(number,'number'),
(operator,plex.TEXT),
(k_print,'print'),
(name,'id'),
(spaces,plex.IGNORE)
])
# open input file for parsing
with open("arithmetic.txt","r") as fp:
# create plex scanner for file fp
scanner = plex.Scanner(lexicon,fp)
# create recursive descent parser
parser = MyParser(scanner)
try:
parser.parse()
except ParseError as e:
_,lineno,charno = scanner.position()
print('Syntax error at line:{} char:{}, {}'.format(lineno,charno+1,e))
except RunError as e:
_,lineno,charno = scanner.position()
print('Runtime error at line:{} char:{}, {}'.format(lineno,charno+1,e))
except plex.errors.PlexError:
_,lineno,charno = scanner.position()
print("Scanner Error at line {} char {}".format(lineno,charno+1))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment