Στο gist αυτό θα αναρτηθούν λύσεις και υποδείξεις κατά τη διεξαγωγή του εργαστηρίου.
Last active
May 28, 2021 13:50
-
-
Save mixstef/912d88a89e10babb95f869d62a3e5b3a to your computer and use it in GitHub Desktop.
Ατζέντα εργαστηρίου Μεταγλωττιστών 28/5/2021
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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)) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| 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)) | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| a = 2 + 7.55*44 | |
| print a | |
| b = 3*(a-99.01) | |
| print b*0.23 | |
| c = 5-3-2 | |
| print c | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| 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