💾 Archived View for pantasya.mooo.com › cgi-bin › ps › archive › Parser-01.py captured on 2023-09-08 at 16:39:52.

View Raw

More Information

-=-=-=-=-=-=-

import os
import random 
import PIL
from PIL import Image, ImageDraw
from datetime import datetime

from palette import pal
from TokenType import TokenType
from my_lib import resize_canvas



class Parser:

  def __init__(self,tokens,image_path):
  
    self.id=id

    self.tokens=tokens
    self.pc=0
    self.glo={}
    self.prm=[]
    self.lab={}
    self.ret=[]
    self.stk=[]    
    self.quit=False

    self.glo["env"]=""
    self.glo["debug"]=0

    self.env=self.glo["env"]

    self.indent=0

    self.image_path=image_path

    if os.path.isfile(self.image_path):
      self.img=Image.open(self.image_path).convert('RGB')
    else:
      self.img=PIL.Image.new(mode="RGB", size=(640,480), color=pal[12])

    self.draw=ImageDraw.Draw(self.img)




  def next(self):
    if self.get_type()==TokenType.EOF:
      self.error("end of file")
    else:
      self.pc+=1
      if self.glo["debug"]==1: print(f"pc: {self.pc}")


  def begin_tag(self,text):
    if self.glo["debug"]==1:
      print("  "*self.indent,end="")   
      print(f"<{text}>")
    self.indent+=1

  def end_tag(self,text):
    self.indent-=1
    if self.glo["debug"]==1:
      print("  "*self.indent,end="")   
      print(f"</{text}>")
  
  def read_labels(self):
    for i in range(len(self.tokens)):
      if self.tokens[i].type==TokenType.LABEL:
        label_name=self.tokens[i].text
        if label_name in self.lab:
          print(f"{self.tokens[i].line}:{self.tokens[i].column}:label redefined: {label_name}")
          quit()
        self.lab[label_name]=i;

  def get_line(self):
    return self.look().line

  def get_column(self):
    return self.look().column

  def error(self,msg):
    print(f"\n{self.get_line()}:{self.get_column()}: {msg}")
    quit()

  def look(self):
    return self.tokens[self.pc]

  def peek(self,offset):
    return self.tokens[self.pc+offset]

  def match(self,type):
    if self.look().type!=type:
      self.error(f"found {self.look().type} expected {type}")      
 
  def get_type(self):
    return self.look().type

  def get_text(self):
    return self.look().text

  def eat(self,type,count=1):
    for _ in range(count):
      self.match(type)
      self.next()
      
  def get_integer(self):
    self.begin_tag("get_integer") 
    result=None
    self.match(TokenType.INTEGER)
    result=int(self.get_text())
    self.next()
    self.end_tag("get_integer") 
    return result

  def get_float(self):
    self.begin_tag("get_float") 
    result=None
    self.match(TokenType.FLOAT)
    result=float(self.get_text())
    self.next()
    self.end_tag("get_float") 
    return result

  def get_string(self):
    self.begin_tag("get_string") 
    result=None
    self.match(TokenType.STRING)
    result=self.get_text()
    self.next()
    self.end_tag("get_string") 
    return result 

  def get_label(self):
    self.begin_tag("get_label") 
    self.match(TokenType.IDENT)
    label_name=self.get_text()
    if label_name not in self.lab:
      self.error(f"undefined label {label_name}")
    self.end_tag("get_label") 
    return label_name 

  def get_none(self):
    self.begin_tag("get_none") 
    self.match(TokenType.NONE)
    self.next()
    self.end_tag("get_none") 
    return None 



  def get_at(self):
    self.begin_tag("get_at") 

    result=None
    count=0
    env=None

    while self.get_type()==TokenType.AT:
      count+=1
      self.next()

    if self.get_type()==TokenType.DOLLAR:
      env=self.glo["env"]    
      self.next()
    
    if self.get_type()==TokenType.PERCENT:        
      self.next()
      index=self.get_integer()
      if index<0 and index>=len(self.prm):
        self.error(f"index out of bounds {index}")
      result=self.prm[index] if env is None else env+"_"+str(self.prm[index])
    elif self.get_type()==TokenType.IDENT:
      result=self.get_text() if env==None else env+"_"+self.get_text()
      self.next()
    else:
      self.error("invalid IDENT")

    for _ in range(count):
      if result not in self.glo:
        self.error(f"undefined identifier {result}")
      result=self.glo[result]
    self.end_tag("get_at") 
    return result



  def get_ident(self):
    self.begin_tag("get_ident")
    ident_name=self.get_text()
    self.next()
    self.end_tag("get_ident") 
    return ident_name



  def get_ident_check(self):
    self.begin_tag("get_ident_check") 
    ident_name=self.get_ident()
    if ident_name not in self.glo:
      self.error(f"get_ident_check: undefined identifier {ident_name}")
    self.end_tag("get_ident_check") 
    return ident_name



  def get_value(self):
    self.begin_tag("get_value") 
    result=None
    if self.get_type()==TokenType.NONE:
      result=self.get_none()
    elif self.get_type()==TokenType.INTEGER:
      result=self.get_integer()
    elif self.get_type()==TokenType.FLOAT:
      result=self.get_float()
    elif self.get_type()==TokenType.STRING:
      result=self.get_string()
    elif self.get_type()==TokenType.IDENT:
      result=self.get_ident_check()
    elif self.get_type() in [TokenType.AT,TokenType.DOLLAR,TokenType.PERCENT]:
      result=self.get_at_check()
    else:
      self.error(f"found {self.get_type()} expected VALUE")
    self.end_tag("get_value") 
    return result



  def check(self,type,text):
    self.begin_tag("check") 
    self.match(TokenType.IDENT)
    if self.get_text()!=text:
      self.error(f"found '{self.get_text()}' expected {text}")  
    self.next()
    self.end_tag("check") 



  def get_label_check(self):
    self.begin_tag("get_label_check") 
    label_name=self.get_label()
    if label_name not in self.lab:
      self.error(f"undefined label {label_name}")
    self.next()
    self.end_tag("get_label_check") 
    return label_name


   
  def do_say(self):
    self.begin_tag("do_say") 
    result=""
    self.check(TokenType.IDENT,"say")
    while self.get_type() not in [TokenType.NEW_LINE,TokenType.EOF]:
      if self.get_type()==TokenType.IDENT:
        ident_name=self.get_ident_check()
        value=self.glo[ident_name]
      else:
        value=self.get_value()
      result+=str(value)
    print(result)
    self.end_tag("do_say") 



  def do_ask(self):
    self.begin_tag("do_ask") 
    result=""
    self.check(TokenType.IDENT,"ask")
    ident_name=self.get_ident_check()
    msg=self.get_value()
    self.set_glo[ident_name]=input(msg)
    self.end_tag("do_ask") 
  
  def do_push(self):
    self.begin_tag("do_push") 
    self.check(TokenType.IDENT,"push")
    while self.get_type() not in [TokenType.NEW_LINE,TokenType.EOF]:
      self.stk.append(self.get_value())
    self.end_tag("do_push") 

  def do_pop(self):
    self.begin_tag("do_pop") 
    self.check(TokenType.IDENT,"pop")
    while self.get_type() not in [TokenType.NEW_LINE,TokenType.EOF]:
      ident_name=self.get_ident_check()
      self.glo[ident_name]=self.stk.pop()
    self.end_tag("do_pop") 

  def do_set(self):
    self.begin_tag("do_set") 
    result=None
    self.check(TokenType.IDENT,"set")
    ident_name=self.get_ident()
    result=self.get_value()
    while self.get_type() not in [TokenType.NEW_LINE,TokenType.EOF]:
      result=str(result)+str(self.get_value())
    self.glo[ident_name]=result
    self.end_tag("do_set") 

  def do_add(self):
    self.begin_tag("do_add") 
    result=0
    self.check(TokenType.IDENT,"add")
    ident_name=self.get_ident_check()
    result=self.glo[ident_name]
    while self.get_type() not in [TokenType.NEW_LINE,TokenType.EOF]:
      value=self.get_value()
      if isinstance(result,str) or isinstance(value,str):
        result=str(result)+str(value)
      else:
        result+=value
    self.glo[ident_name]=result
    self.end_tag("do_add") 

  def do_sub(self):
    self.begin_tag("do_sub") 
    result=None
    self.check(TokenType.IDENT,"sub")
    ident_name=self.get_ident_check()
    result=self.glo[ident_name]
    while self.get_type() not in [TokenType.NEW_LINE,TokenType.EOF]:
      value=self.get_value()
      result-=value
    self.glo[ident_name]=result
    self.end_tag("do_sub") 



  def do_mul(self):
    self.begin_tag("do_mul") 
    result=None
    self.check(TokenType.IDENT,"mul")
    value=self.get_at()
    while self.get_type() not in [TokenType.NEW_LINE,TokenType.EOF]:
      value=self.get_value()
      result*=value
    self.glo[ident_name]=result
    self.end_tag("do_mul") 



  def do_div(self):
    self.begin_tag("do_div") 
    result=None
    self.check(TokenType.IDENT,"div")
    ident_name=self.get_ident()
    self.next()
    result=self.glo[ident_name]
    while self.get_type() not in [TokenType.NEW_LINE,TokenType.EOF]:
      value=self.get_value()
      if value!=0:
        result/=value
      else:
        self.error("divide by zero")
    self.glo[ident_name]=result
    self.end_tag("do_div") 

  def do_mod(self):
    self.begin_tag("do_mod") 
    result=None
    self.check(TokenType.IDENT,"mod")
    ident_name=self.get_ident_check()
    value=self.get_value()
    self.glo[ident_name]%=value
    self.end_tag("do_mod") 


  def do_jmp(self):
    self.begin_tag("do_jmp") 
    self.check(TokenType.IDENT,"jmp")
    label_name=self.get_ident()
    if label_name not in self.lab:
      self.error(f"undefined label {label_name}")
    self.pc=self.lab[label_name]
    self.next()
    self.end_tag("do_jmp") 



  def do_call(self):
    self.begin_tag("do_call") 
    self.check(TokenType.IDENT,"call")
    label_name=self.get_label_check();

    prm=[]
    while self.get_type() not in [TokenType.NEW_LINE,TokenType.EOF]:
      value=self.get_value()
      prm.append(value)

    self.ret.append(
      {
        "env":self.glo["env"],
        "prm":self.prm,
        "pc":self.pc
      }
    )

    self.prm=prm
    self.glo["env"]=label_name
    self.pc=self.lab[label_name]

    self.end_tag("do_call") 

    
  def do_ret(self):
    self.begin_tag("do_ret") 
    self.check(TokenType.IDENT,"ret")
    ret=self.ret.pop()
    self.glo["env"]=ret["env"]
    self.prm=ret["prm"]
    self.pc=ret["pc"]
    if self.glo["debug"]==1: print("</ret>") 
    self.end_tag("do_ret") 



  def do_and(self):
    self.begin_tag("do_and") 
    self.check(TokenType.IDENT,"and")
    ident_name=self.get_ident_check()
    a=int(self.get_value())
    b=int(self.get_value())
    self.glo[ident_name]=a & b
    self.end_tag("do_and") 

  def do_or(self):
    self.begin_tag("do_or") 
    self.check(TokenType.IDENT,"or")
    ident_name=self.get_ident_check()
    a=int(self.get_value())
    b=int(self.get_value())
    self.glo[ident_name]=a | b
    self.end_tag("do_or") 

  def do_not(self):
    self.begin_tag("do_not") 
    self.check(TokenType.IDENT,"not")
    ident_name=self.get_ident_check()
    self.glo[ident_name]=~self.glo[ident_name]
    self.end_tag("do_not") 

 
  def do_jeq(self):
    self.begin_tag("do_jeq") 
    self.check(TokenType.IDENT,"jeq")
    label_name=self.get_label_check()
    a=self.get_value()
    b=self.get_value()
    if a==b:
      self.pc=self.lab[label_name]
    self.end_tag("do_jeq") 

  def do_jne(self):
    self.begin_tag("do_jne") 
    self.check(TokenType.IDENT,"jne")
    label_name=self.get_label_check()
    a=self.get_value()
    b=self.get_value()
    if a!=b:
      self.pc=self.lab[label_name]
    self.end_tag("do_jne") 

  def do_jl(self):
    self.begin_tag("do_jl") 
    self.check(TokenType.IDENT,"jl")
    label_name=self.get_label_check()
    a=self.get_value()
    b=self.get_value()
    if a<b:
      self.pc=self.lab[label_name]
    self.end_tag("do_jl") 

  def do_jle(self):
    self.begin_tag("do_jle") 
    self.check(TokenType.IDENT,"jle")
    label_name=self.get_label_check()
    a=self.get_value()
    b=self.get_value()
    if a<=b:
      self.pc=self.lab[label_name]
    self.end_tag("do_jle") 

  def do_jg(self):
    self.begin_tag("do_jg") 
    self.check(TokenType.IDENT,"jg")
    label_name=self.get_label_check()
    a=self.get_value()
    b=self.get_value()
    if a>b:
      self.pc=self.lab[label_name]
    self.end_tag("do_jg") 
    
  def do_jge(self):
    self.begin_tag("do_jge") 
    self.check(TokenType.IDENT,"jge")
    label_name=self.get_label_check()
    a=self.get_value()
    b=self.get_value()
    if a>=b:
      self.pc=self.lab[label_name]
    self.end_tag("do_jge") 

  def do_int(self):
    self.begin_tag("do_int") 
    self.check(TokenType.IDENT,"int")
    ident_name=self.get_ident_check()
    value=int(self.get_value())
    self.glo[ident_name]=value
    self.end_tag("do_int") 

  def do_flt(self):
    self.begin_tag("do_flt") 
    self.check(TokenType.IDENT,"flt")
    ident_name=self.get_ident_check()
    value=float(self.get_value())
    self.glo[ident_name]=value
    self.end_tag("do_flt") 

  def do_str(self):
    self.begin_tag("do_str") 
    self.check(TokenType.IDENT,"str")
    ident_name=self.get_ident_check()
    value=str(self.get_value())
    self.glo[ident_name]=value
    self.end_tag("do_str") 

  def do_rnd(self):
    self.begin_tag("do_rnd") 
    self.check(TokenType.IDENT,"rnd")
    ident_name=self.get_ident_check()
    s=self.get_value()
    e=self.get_value()   
    self.glo[ident_name]=random.randint(s,e)
    self.end_tag("do_rnd") 

  def do_end(self):
    self.begin_tag("do_end") 
    self.check(TokenType.IDENT,"end")
    self.quit=True
    self.end_tag("do_end") 







  def do_line(self):
    self.begin_tag("do_line") 
    self.check(TokenType.IDENT,"line")
    
    x0=self.get_value()
    y0=self.get_value()
    x1=self.get_value()
    y1=self.get_value()
    f=self.get_value()
    w=self.get_value()

    if self.glo["debug"]==1:
      print(f"line {x0} {y0} {x1} {y1} {f} {w}")

    try:
      self.draw.line((x0,y0,x1,y1),fill=None if f==None else pal[f],width=w)      
      self.img.save(self.image_path)
    except:
      self.error("Drawing Error")
    self.end_tag("do_line") 



  def do_oval(self):
    self.begin_tag("do_oval") 
    self.check(TokenType.IDENT,"oval")
    
    x0=self.get_value()
    y0=self.get_value()
    x1=self.get_value()
    y1=self.get_value()
    f=self.get_value()
    o=self.get_value()    
    w=self.get_value()

    print(f"oval {x0} {y0} {x1} {y1} {f} {o} {w}")

    try:
      self.draw.ellipse((x0,y0,x1,y1),fill=None if f==None else pal[f],outline=None if o==None else pal[o],width=w)      
      self.img.save(self.image_path)
    except:
      self.error("Drawing Error")
    self.end_tag("do_oval") 



  def do_rect(self):
    self.begin_tag("do_rect") 
    self.check(TokenType.IDENT,"rect")
    
    x0=self.get_value()
    y0=self.get_value()
    x1=self.get_value()
    y1=self.get_value()
    f=self.get_value()
    o=self.get_value()    
    w=self.get_value()

    print(f"rect {x0} {y0} {x1} {y1} {f} {o} {w}")

    try:
      self.draw.rectangle((x0,y0,x1,y1),fill=None if f==None else pal[f],outline=None if o==None else pal[o],width=w)      
      self.img.save(self.image_path)
    except:
      self.error("Drawing Error")
    self.end_tag("do_rect") 



  def do_arc(self):
    self.begin_tag("do_arc") 
    self.check(TokenType.IDENT,"arc")
    
    x0=self.get_value()
    y0=self.get_value()
    x1=self.get_value()
    y1=self.get_value()
    s=self.get_value()
    e=self.get_value()
    f=self.get_value()
    w=self.get_value()

    print(f"arc {x0} {y0} {x1} {y1} {f} {w}")

    try:
      self.draw.arc((x0,y0,x1,y1),start=s,end=e,fill=None if f==None else pal[f],width=w)      
      self.img.save(self.image_path)
    except:
      self.error("Drawing Error")
    self.end_tag("do_arc") 



  def do_chord(self):
    self.begin_tag("do_chord") 
    self.check(TokenType.IDENT,"chord")
    
    x0=self.get_value()
    y0=self.get_value()
    x1=self.get_value()
    y1=self.get_value()
    s=self.get_value()
    e=self.get_value()
    f=self.get_value()
    o=self.get_value()    
    w=self.get_value()

    print(f"chord {x0} {y0} {x1} {y1} {f} {o} {w}")

    try:
      self.draw.chord((x0,y0,x1,y1),start=s,end=e,fill=None if f==None else pal[f],outline=None if o==None else pal[f],width=w)      
      self.img.save(self.image_path)
    except:
      self.error("Drawing Error")
    self.end_tag("do_chord") 



  def do_pie(self):
    self.begin_tag("do_pie") 
    self.check(TokenType.IDENT,"pie")
    
    x0=self.get_value()
    y0=self.get_value()
    x1=self.get_value()
    y1=self.get_value()
    s=self.get_value()
    e=self.get_value()
    f=self.get_value()
    o=self.get_value()    
    w=self.get_value()

    print(f"pie {x0} {y0} {x1} {y1} {f} {o} {w}")

    try:
      self.draw.pieslice((x0,y0,x1,y1),start=s,end=e,fill=None if f==None else pal[f],outline=None if o==None else pal[f],width=w)      
      self.img.save(self.image_path)
    except:
      self.error("Drawing Error")
    self.end_tag("do_pie") 



  def do_poly(self):
    self.begin_tag("do_poly") 
    self.check(TokenType.IDENT,"poly")

    count=0
    start=self.pc
    while self.get_type() not in [TokenType.NEW_LINE,TokenType.EOF]:
      count+=1

    p=[]
    for i in range(0,count-3,2):
      p.append=((self.get_value(),self.get_value()))

    f=self.get_value()
    o=self.get_value()    
    w=self.get_value()

    print(f"poly {p} {f} {o} {w}")

    try:
      self.draw.polygon(p,start=s,end=e,fill=None if f==None else pal[f],outline=None if o==None else pal[f],width=w)      
      self.img.save(self.image_path)
    except:
      self.error("Drawing Error")
    self.end_tag("do_poly") 


  def do_clear(self):
    self.begin_tag("do_clear") 
    self.check(TokenType.IDENT,"clear")
    
    x0=0
    y0=0
    x1,y1=self.img.size
    f=self.get_value()

    print(f"clear {f}")

    try:
      self.draw.rectangle((x0,y0,x1,y1),fill=None if f==None else pal[f])      
      self.img.save(self.image_path)
    except:
      self.error("Drawing Error")
    self.end_tag("do_clear") 


  def do_datetime(self):
    self.begin_tag("do_datetime") 
    self.check(TokenType.IDENT,"datetime")
    
    Y=self.get_ident_check()
    M=self.get_ident_check()
    D=self.get_ident_check()
    h=self.get_ident_check()
    m=self.get_ident_check()
    s=self.get_ident_check()
    ms=self.get_ident_check()

    now=datetime.now()

    self.glo[Y]=now.year
    self.glo[M]=now.month
    self.glo[D]=now.day
    self.glo[h]=now.hour
    self.glo[m]=now.minute
    self.glo[s]=now.second
    self.glo[ms]=now.microsecond
    self.end_tag("do_datetime") 
        


  def do_setsize(self):
    self.begin_tag("do_setsize") 
    self.check(TokenType.IDENT,"setsize")

    w=self.get_value()
    h=self.get_value()

    resize_canvas(self.image_path,self.image_path,w,h)

    self.img=Image.open(self.image_path).convert('RGB')
    self.end_tag("do_setsize") 



  def do_getsize(self):
    self.begin_tag("do_getsize") 
    self.check(TokenType.IDENT,"getsize")

    ident_name1=self.get_ident_check()
    ident_name2=self.get_ident_check()

    w,h=self.img.size

    self.glo[ident_name1]=w
    self.glo[ident_name2]=h
    self.end_tag("do_getsize") 



  def do_debug(self):
    self.check(TokenType.IDENT,"debug")
    self.glo["debug"]=self.get_integer()

  def do_globals(self):
    self.begin_tag("do_globals") 
    self.check(TokenType.IDENT,"globals")
    for key in self.glo:
      print(f"{key} =",f"\"{self.glo[key]}\"" if isinstance(self.glo[key],str) else self.glo[key])
    self.end_tag("do_globals") 

  def do_labels(self):
    self.begin_tag("do_labels") 
    self.check(TokenType.IDENT,"labels")
    for key in self.lab:
      print(key,self.lab[key])
    self.end_tag("do_labels") 

  def do_params(self):
    self.begin_tag("do_params") 
    self.check(TokenType.IDENT,"params")
    for i in range(len(self.prm)):
      print(f"%{i} = {self.prm[i]}")
    self.end_tag("do_params") 

  def do_tokens(self):
    self.begin_tag("do_tokens") 
    self.check(TokenType.IDENT,"tokens")
    for i in range(len(self.tokens)):
      print(f"{i} {self.tokens[i]}")
    self.end_tag("do_tokens") 



  def eval(self):
    self.begin_tag("eval") 
              
    if self.get_type()==TokenType.IDENT:
    
      if self.get_text()=="say":
        self.do_say()
      elif self.get_text()=="ask":
        self.do_ask()
      elif self.get_text()=="push":
        self.do_push()
      elif self.get_text()=="pop":
        self.do_pop()
      elif self.get_text()=="set":
        self.do_set()
      elif self.get_text()=="add":
        self.do_add()
      elif self.get_text()=="sub":
        self.do_sub()
      elif self.get_text()=="mul":
        self.do_mul()
      elif self.get_text()=="div":
        self.do_div()
      elif self.get_text()=="mod":
        self.do_mod()
      elif self.get_text()=="and":
        self.do_and()
      elif self.get_text()=="or":
        self.do_or()
      elif self.get_text()=="not":
        self.do_not()
      elif self.get_text()=="jmp":
        self.do_jmp()
      elif self.get_text()=="jeq":
        self.do_jeq()
      elif self.get_text()=="jne":
        self.do_jne()
      elif self.get_text()=="jl":
        self.do_jl()
      elif self.get_text()=="jle":
        self.do_jle()
      elif self.get_text()=="jg":
        self.do_jg()
      elif self.get_text()=="jge":
        self.do_jge()
      elif self.get_text()=="call":
        self.do_call()
      elif self.get_text()=="ret":
        self.do_ret()
      elif self.get_text()=="int":
        self.do_int()
      elif self.get_text()=="flt":
        self.do_flt()
      elif self.get_text()=="str":
        self.do_str()
      elif self.get_text()=="end":
        self.do_end()
      elif self.get_text()=="line":
        self.do_line()
      elif self.get_text()=="oval":
        self.do_oval()
      elif self.get_text()=="rect":
        self.do_rect()
      elif self.get_text()=="arc":
        self.do_aec()
      elif self.get_text()=="chord":
        self.do_chord()
      elif self.get_text()=="pie":
        self.do_pie()
      elif self.get_text()=="poly":
        self.do_poly()
      elif self.get_text()=="clear":
        self.do_clear()
      elif self.get_text()=="rnd":
        self.do_rnd()
      elif self.get_text()=="datetime":
        self.do_datetime()
      elif self.get_text()=="setsize":
        self.do_setsize()
      elif self.get_text()=="getsize":
        self.do_getsize()
      elif self.get_text()=="debug":
        self.do_debug()
      elif self.get_text()=="labels":
        self.do_labels()
      elif self.get_text()=="globals":
        self.do_globals()
      elif self.get_text()=="params":
        self.do_params()
      elif self.get_text()=="tokens":
        self.do_tokens()
      else:
        self.error(f"invalid command {self.get_text()}")
    self.end_tag("eval") 



  def parse(self):
    self.read_labels()
    while not self.quit and not self.get_type()==TokenType.EOF:

      while self.get_type() in [TokenType.NEW_LINE,TokenType.LABEL,TokenType.COMMENT]:
        self.next()

      self.eval()