Ejemplo n.º 1
0
class Compiler():
  
  #valid token types which can comprise a <Statement>
  valid_statement_tokens = [
    Token.LBLOCK, Token.VAR, Token.CONST, Token.IDENTIFIER, Token.IF,
    Token.INPUT, Token.OUTPUT, Token.WHILE, Token.SEMI]
  
  #valid token types which can comprise an <Expression>
  valid_expression_tokens = [
    Token.NUMBER, Token.IDENTIFIER, Token.LPAREN, Token.RPAREN,
    Token.PLUS, Token.MINUS, Token.DIV, Token.MUL, Token.TRUE, Token.FALSE]
  
  #valid token types which can comprise a <Comparison> token
  valid_comparison_tokens = [
    Token.LTEQ, Token.GTEQ, Token.GT,
    Token.LT, Token.EQUAL, Token.NOTEQUAL]
  
  def __init__(self, tokens):
    """
    Compiler initializer.
    tokens (list): Tokens produced by the parser
    """
    self.tokens = tokens
    self.compiled = list() #compiled code generated by run()
  
  def run(self):
    """
    Compiles the code
    """
    if len(self.tokens) == 0: #case when the program is empty
      self.compiled = ['.']
      return
    preserved_tokens = self.tokens[:] #preserve the tokens because they're consumed during compilation
    self.program = Program(self).build() #begin recursive descent parsing
    self.tokens = preserved_tokens #restore the tokens
    self.program.clean() #begin the recursive clean/modification process (to translate to PL/0)
    self.program.compile() #generate the compiled PL/0 code
  
  def error(self, text):
    """
    The compiler found a grammar error and will report it to the user. All errors are fatal
    text (string): Error message to report to user.
    """
    quit('LINE ' + str(self.tokens[0].line) + ' (Token: "' + self.tokens[0].text + '") ERROR <' + callee().lstrip('_').upper() + '> : ' + text)
  
  def next(self, pos = 0):
    """
    Return the type of token pos positions ahead in the token list.
    pos (int, optional): The position to lookup within the tokens.
    """
    return "<NONE>" if len(self.tokens) <= pos else self.tokens[pos].type
  
  def skip(self, pos = 1):
    """
    Tell the compiler to skip/discard pos number of tokens.
    pos (int, optional): The number of tokens to skip/discard.
    """
    self.tokens = self.tokens[pos:]
    
  def __str__(self):
    """
    String representation of the compiler
    """
    return ''.join([str(i) for i in self.compiled])