changeset 98:3f772feb12ef

movage
author windel
date Mon, 24 Dec 2012 13:57:00 +0100
parents 5a965e9664f2
children 6efbeb903777
files python/ide.py python/ppci/frontends/ks/lexer.py python/ppci/frontends/ks/parser.py python/ppci/frontends/ksparser.py python/ppci/frontends/lexer.py
diffstat 5 files changed, 256 insertions(+), 256 deletions(-) [+]
line wrap: on
line diff
--- a/python/ide.py	Mon Dec 24 13:32:54 2012 +0100
+++ b/python/ide.py	Mon Dec 24 13:57:00 2012 +0100
@@ -7,9 +7,9 @@
 from PyQt4.QtGui import *
 
 # Compiler imports:
-sys.path.insert(0, os.path.join('..','libs'))
+sys.path.insert(0, '.') # Add current path to the path string
 from project import Project
-from compiler import Compiler
+from ppci import Compiler
 from widgets import CodeEdit, AstViewer
 
 lcfospng = base64.decodestring(b'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A\n/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEhMKBk7B678AAAA/SURBVFjD\n7dbBCQAgDATBi9h/y7EFA4Kf2QLCwH1S6XQu6sqoujublc8BAAAAAAAAAAB8B+zXT6YJAAAAAKYd\nWSgFQNUyijIAAAAASUVORK5CYII=\n')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/ppci/frontends/ks/lexer.py	Mon Dec 24 13:57:00 2012 +0100
@@ -0,0 +1,71 @@
+import collections
+import re
+from .errors import CompilerException
+
+"""
+ Lexical analyzer part. Splits the input character stream into tokens.
+"""
+
+# Token is used in the lexical analyzer:
+Token = collections.namedtuple('Token', 'typ val row col')
+
+keywords = ['and', 'array', 'begin', 'by', 'case', 'const', 'div', 'do', \
+   'else', 'elsif', 'end', 'false', 'for', 'if', 'import', 'in', 'is', \
+   'mod', 'module', 'nil', 'not', 'of', 'or', 'pointer', 'procedure', \
+   'record', 'repeat', 'return', 'then', 'to', 'true', 'type', 'until', 'var', \
+   'while', 'asm' ]
+
+def tokenize(s):
+     """
+       Tokenizer, generates an iterator that
+       returns tokens!
+
+       This GREAT example was taken from python re doc page!
+     """
+     tok_spec = [
+       ('REAL', r'\d+\.\d+'),
+       ('HEXNUMBER', r'0x[\da-fA-F]+'),
+       ('NUMBER', r'\d+'),
+       ('ID', r'[A-Za-z][A-Za-z\d_]*'),
+       ('NEWLINE', r'\n'),
+       ('SKIP', r'[ \t]'),
+       ('COMMENTS', r'{.*}'),
+       ('LEESTEKEN', r':=|[\.,=:;\-+*\[\]/\(\)]|>=|<=|<>|>|<'),
+       ('STRING', r"'.*?'")
+     ]
+     tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tok_spec)
+     gettok = re.compile(tok_re).match
+     line = 1
+     pos = line_start = 0
+     mo = gettok(s)
+     while mo is not None:
+       typ = mo.lastgroup
+       val = mo.group(typ)
+       if typ == 'NEWLINE':
+         line_start = pos
+         line += 1
+       elif typ == 'COMMENTS':
+         pass
+       elif typ != 'SKIP':
+         if typ == 'ID':
+           if val in keywords:
+             typ = val
+         elif typ == 'LEESTEKEN':
+           typ = val
+         elif typ == 'NUMBER':
+           val = int(val)
+         elif typ == 'HEXNUMBER':
+           val = int(val[2:], 16)
+           typ = 'NUMBER'
+         elif typ == 'REAL':
+           val = float(val)
+         elif typ == 'STRING':
+           val = val[1:-1]
+         yield Token(typ, val, line, mo.start()-line_start)
+       pos = mo.end()
+       mo = gettok(s, pos)
+     if pos != len(s):
+       col = pos - line_start
+       raise CompilerException('Unexpected character {0}'.format(s[pos]), line, col)
+     yield Token('END', '', line, 0)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/ppci/frontends/ks/parser.py	Mon Dec 24 13:57:00 2012 +0100
@@ -0,0 +1,183 @@
+"""
+  This module define a grammar for the 'K#' language.
+"""
+
+from .nodes import *
+from .errors import CompilerException, Error
+from .modules import loadModule
+from .display import printNode
+from .builtin import *
+from . import assembler
+
+class Grammar:
+   # TODO: implement some base class?
+   pass
+
+class Parser:
+   #TODO
+   pass
+
+class KsParser(Parser):
+   def __init__(self):
+      self.loadGrammar(KsGrammar)
+
+# For now, try to parse an expression as test case:
+class KsGrammer(Grammar):
+
+   def __init__(self):
+      pass
+
+   # Parsing expressions:
+   """
+     grammar of expressions:
+     expression       = term { addoperator term }
+     addoperator      = '+' | '-'
+     term             = factor { muloperator factor }
+     muloperator      = '*' | '/'
+     factor           = number | "(" expression ")"
+   """
+
+   @rule(Term)
+   def Expression1(self, term):
+      return Expression(term)
+
+   @rule(Term, AddOperator, Term)
+   def Expression2(self, term1, op, term2):
+      return Expression(term1, op, term2)
+
+   # Parsing arithmatic expressions:
+   def parseTerm(self):
+       a = self.parseFactor()
+       while self.token.typ in ['*', '/', 'mod', 'div', 'and']:
+           loc = self.getLocation()
+           op = self.Consume()
+           b = self.parseTerm()
+           # Type determination and checking:
+           if op in ['mod', 'div']:
+              if not isType(a.typ, integer):
+                 self.Error('First operand should be integer, not {0}'.format(a.typ))
+              if not isType(b.typ, integer):
+                 self.Error('Second operand should be integer, not {0}'.format(b.typ))
+              typ = integer
+           elif op == '*':
+              if isType(a.typ, integer) and isType(b.typ, integer):
+                 typ = integer
+              elif isType(a.typ, real) or isType(b.typ, real):
+                 if isType(a.typ, integer):
+                    # Automatic type cast
+                    a = Unop(a, 'INTTOREAL', real)
+                 if isType(b.typ, integer):
+                    b = Unop(b, 'INTTOREAL', real)
+                 if not isType(a.typ, real):
+                    self.Error('first operand must be a real!')
+                 if not isType(b.typ, real):
+                    self.Error('second operand must be a real!')
+                 typ = real
+              else:
+                 self.Error('Unknown operands for multiply: {0}, {1}'.format(a, b))
+           elif op == '/':
+              # Division always yields a real result, for integer division use div
+              if isType(a.typ, integer):
+                 # Automatic type cast
+                 a = Unop(a, 'INTTOREAL', real)
+              if isType(b.typ, integer):
+                 b = Unop(b, 'INTTOREAL', real)
+              if not isType(a.typ, real):
+                 self.Error('first operand must be a real!')
+              if not isType(b.typ, real):
+                 self.Error('second operand must be a real!')
+              typ = real
+           elif op == 'and':
+              if not isType(a.typ, boolean):
+                 self.Error('First operand of and must be boolean')
+              if not isType(b.typ, boolean):
+                 self.Error('Second operand of and must be boolean')
+              typ = boolean
+           else:
+              self.Error('Unknown operand {0}'.format(op))
+
+           a = self.setLocation(Binop(a, op, b, typ), loc)
+       return a
+
+   @rule(
+   def parseFactor(self):
+      if self.hasConsumed('('):
+         e = self.parseExpression()
+         self.Consume(')')
+         return e
+      elif self.token.typ == 'NUMBER':
+         loc = self.getLocation() 
+         val = self.Consume('NUMBER')
+         return self.setLocation(Constant(val, integer), loc)
+      elif self.token.typ == 'REAL':
+         loc = self.getLocation()
+         val = self.Consume('REAL')
+         return self.setLocation(Constant(val, real), loc)
+      elif self.token.typ == 'CHAR':
+          val = self.Consume('CHAR')
+          return Constant(val, char)
+      elif self.token.typ in ['true', 'false']:
+         val = self.Consume()
+         val = True if val == 'true' else False
+         return Constant(val, boolean)
+      elif self.hasConsumed('nil'):
+         return Constant(0, NilType())
+      elif self.hasConsumed('not'):
+         f = self.parseFactor()
+         if not isType(f.typ, boolean):
+            self.Error('argument of boolean negation must be boolean type')
+         return Unop(f, 'not', boolean)
+      elif self.token.typ == 'ID':
+          designator = self.parseDesignator()
+          # TODO: handle functions different here?
+          if self.token.typ == '(' and type(designator.typ) is ProcedureType:
+             return self.parseProcedureCall(designator)
+          else:
+             return designator
+      else:
+         self.Error('Expected NUMBER, ID or ( expr ), got'+str(self.token))
+
+   def parseSimpleExpression(self):
+      """ Arithmatic expression """
+      if self.token.typ in ['+', '-']:
+         # Handle the unary minus
+         op = self.Consume()
+         a = self.parseTerm()
+         typ = a.typ
+         if not isType(typ,real) and not isType(typ, integer):
+            self.Error('Unary minus or plus can be only applied to real or integers')
+         if op == '-':
+            a = Unop(a, op, typ)
+      else:
+         a = self.parseTerm()
+      while self.token.typ in ['+', '-', 'or']:
+           loc = self.getLocation()
+           op = self.Consume()
+           b = self.parseTerm()
+           if op in ['+', '-']:
+              if isType(a.typ, real) or isType(b.typ, real):
+                 typ = real
+                 if isType(a.typ, integer):
+                    # Automatic type cast
+                    a = Unop(a, 'INTTOREAL', real)
+                 if not isType(a.typ, real):
+                    self.Error('first operand must be a real!')
+                 if isType(b.typ, integer):
+                    b = Unop(b, 'INTTOREAL', real)
+                 if not isType(b.typ, real):
+                    self.Error('second operand must be a real!')
+              elif isType(a.typ, integer) and isType(b.typ, integer):
+                 typ = integer
+              else:
+                 self.Error('Invalid types {0} and {1}'.format(a.typ, b.typ))
+           elif op == 'or':
+              if not isType(a.typ, boolean):
+                 self.Error('first operand must be boolean for or operation')
+              if not isType(b.typ, boolean):
+                 self.Error('second operand must be boolean for or operation')
+              typ = boolean
+           else:
+              self.Error('Unknown operand {0}'.format(op))
+           a = self.setLocation(Binop(a, op, b, typ), loc)
+      return a
+
--- a/python/ppci/frontends/ksparser.py	Mon Dec 24 13:32:54 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,183 +0,0 @@
-"""
-  This module define a grammar for the 'K#' language.
-"""
-
-from .nodes import *
-from .errors import CompilerException, Error
-from .modules import loadModule
-from .display import printNode
-from .builtin import *
-from . import assembler
-
-class Grammar:
-   # TODO: implement some base class?
-   pass
-
-class Parser:
-   #TODO
-   pass
-
-class KsParser(Parser):
-   def __init__(self):
-      self.loadGrammar(KsGrammar)
-
-# For now, try to parse an expression as test case:
-class KsGrammer(Grammar):
-
-   def __init__(self):
-      pass
-
-   # Parsing expressions:
-   """
-     grammar of expressions:
-     expression       = term { addoperator term }
-     addoperator      = '+' | '-'
-     term             = factor { muloperator factor }
-     muloperator      = '*' | '/'
-     factor           = number | "(" expression ")"
-   """
-
-   @rule(Term)
-   def Expression1(self, term):
-      return Expression(term)
-
-   @rule(Term, AddOperator, Term)
-   def Expression2(self, term1, op, term2):
-      return Expression(term1, op, term2)
-
-   # Parsing arithmatic expressions:
-   def parseTerm(self):
-       a = self.parseFactor()
-       while self.token.typ in ['*', '/', 'mod', 'div', 'and']:
-           loc = self.getLocation()
-           op = self.Consume()
-           b = self.parseTerm()
-           # Type determination and checking:
-           if op in ['mod', 'div']:
-              if not isType(a.typ, integer):
-                 self.Error('First operand should be integer, not {0}'.format(a.typ))
-              if not isType(b.typ, integer):
-                 self.Error('Second operand should be integer, not {0}'.format(b.typ))
-              typ = integer
-           elif op == '*':
-              if isType(a.typ, integer) and isType(b.typ, integer):
-                 typ = integer
-              elif isType(a.typ, real) or isType(b.typ, real):
-                 if isType(a.typ, integer):
-                    # Automatic type cast
-                    a = Unop(a, 'INTTOREAL', real)
-                 if isType(b.typ, integer):
-                    b = Unop(b, 'INTTOREAL', real)
-                 if not isType(a.typ, real):
-                    self.Error('first operand must be a real!')
-                 if not isType(b.typ, real):
-                    self.Error('second operand must be a real!')
-                 typ = real
-              else:
-                 self.Error('Unknown operands for multiply: {0}, {1}'.format(a, b))
-           elif op == '/':
-              # Division always yields a real result, for integer division use div
-              if isType(a.typ, integer):
-                 # Automatic type cast
-                 a = Unop(a, 'INTTOREAL', real)
-              if isType(b.typ, integer):
-                 b = Unop(b, 'INTTOREAL', real)
-              if not isType(a.typ, real):
-                 self.Error('first operand must be a real!')
-              if not isType(b.typ, real):
-                 self.Error('second operand must be a real!')
-              typ = real
-           elif op == 'and':
-              if not isType(a.typ, boolean):
-                 self.Error('First operand of and must be boolean')
-              if not isType(b.typ, boolean):
-                 self.Error('Second operand of and must be boolean')
-              typ = boolean
-           else:
-              self.Error('Unknown operand {0}'.format(op))
-
-           a = self.setLocation(Binop(a, op, b, typ), loc)
-       return a
-
-   @rule(
-   def parseFactor(self):
-      if self.hasConsumed('('):
-         e = self.parseExpression()
-         self.Consume(')')
-         return e
-      elif self.token.typ == 'NUMBER':
-         loc = self.getLocation() 
-         val = self.Consume('NUMBER')
-         return self.setLocation(Constant(val, integer), loc)
-      elif self.token.typ == 'REAL':
-         loc = self.getLocation()
-         val = self.Consume('REAL')
-         return self.setLocation(Constant(val, real), loc)
-      elif self.token.typ == 'CHAR':
-          val = self.Consume('CHAR')
-          return Constant(val, char)
-      elif self.token.typ in ['true', 'false']:
-         val = self.Consume()
-         val = True if val == 'true' else False
-         return Constant(val, boolean)
-      elif self.hasConsumed('nil'):
-         return Constant(0, NilType())
-      elif self.hasConsumed('not'):
-         f = self.parseFactor()
-         if not isType(f.typ, boolean):
-            self.Error('argument of boolean negation must be boolean type')
-         return Unop(f, 'not', boolean)
-      elif self.token.typ == 'ID':
-          designator = self.parseDesignator()
-          # TODO: handle functions different here?
-          if self.token.typ == '(' and type(designator.typ) is ProcedureType:
-             return self.parseProcedureCall(designator)
-          else:
-             return designator
-      else:
-         self.Error('Expected NUMBER, ID or ( expr ), got'+str(self.token))
-
-   def parseSimpleExpression(self):
-      """ Arithmatic expression """
-      if self.token.typ in ['+', '-']:
-         # Handle the unary minus
-         op = self.Consume()
-         a = self.parseTerm()
-         typ = a.typ
-         if not isType(typ,real) and not isType(typ, integer):
-            self.Error('Unary minus or plus can be only applied to real or integers')
-         if op == '-':
-            a = Unop(a, op, typ)
-      else:
-         a = self.parseTerm()
-      while self.token.typ in ['+', '-', 'or']:
-           loc = self.getLocation()
-           op = self.Consume()
-           b = self.parseTerm()
-           if op in ['+', '-']:
-              if isType(a.typ, real) or isType(b.typ, real):
-                 typ = real
-                 if isType(a.typ, integer):
-                    # Automatic type cast
-                    a = Unop(a, 'INTTOREAL', real)
-                 if not isType(a.typ, real):
-                    self.Error('first operand must be a real!')
-                 if isType(b.typ, integer):
-                    b = Unop(b, 'INTTOREAL', real)
-                 if not isType(b.typ, real):
-                    self.Error('second operand must be a real!')
-              elif isType(a.typ, integer) and isType(b.typ, integer):
-                 typ = integer
-              else:
-                 self.Error('Invalid types {0} and {1}'.format(a.typ, b.typ))
-           elif op == 'or':
-              if not isType(a.typ, boolean):
-                 self.Error('first operand must be boolean for or operation')
-              if not isType(b.typ, boolean):
-                 self.Error('second operand must be boolean for or operation')
-              typ = boolean
-           else:
-              self.Error('Unknown operand {0}'.format(op))
-           a = self.setLocation(Binop(a, op, b, typ), loc)
-      return a
-
--- a/python/ppci/frontends/lexer.py	Mon Dec 24 13:32:54 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-import collections
-import re
-from .errors import CompilerException
-
-"""
- Lexical analyzer part. Splits the input character stream into tokens.
-"""
-
-# Token is used in the lexical analyzer:
-Token = collections.namedtuple('Token', 'typ val row col')
-
-keywords = ['and', 'array', 'begin', 'by', 'case', 'const', 'div', 'do', \
-   'else', 'elsif', 'end', 'false', 'for', 'if', 'import', 'in', 'is', \
-   'mod', 'module', 'nil', 'not', 'of', 'or', 'pointer', 'procedure', \
-   'record', 'repeat', 'return', 'then', 'to', 'true', 'type', 'until', 'var', \
-   'while', 'asm' ]
-
-def tokenize(s):
-     """
-       Tokenizer, generates an iterator that
-       returns tokens!
-
-       This GREAT example was taken from python re doc page!
-     """
-     tok_spec = [
-       ('REAL', r'\d+\.\d+'),
-       ('HEXNUMBER', r'0x[\da-fA-F]+'),
-       ('NUMBER', r'\d+'),
-       ('ID', r'[A-Za-z][A-Za-z\d_]*'),
-       ('NEWLINE', r'\n'),
-       ('SKIP', r'[ \t]'),
-       ('COMMENTS', r'{.*}'),
-       ('LEESTEKEN', r':=|[\.,=:;\-+*\[\]/\(\)]|>=|<=|<>|>|<'),
-       ('STRING', r"'.*?'")
-     ]
-     tok_re = '|'.join('(?P<%s>%s)' % pair for pair in tok_spec)
-     gettok = re.compile(tok_re).match
-     line = 1
-     pos = line_start = 0
-     mo = gettok(s)
-     while mo is not None:
-       typ = mo.lastgroup
-       val = mo.group(typ)
-       if typ == 'NEWLINE':
-         line_start = pos
-         line += 1
-       elif typ == 'COMMENTS':
-         pass
-       elif typ != 'SKIP':
-         if typ == 'ID':
-           if val in keywords:
-             typ = val
-         elif typ == 'LEESTEKEN':
-           typ = val
-         elif typ == 'NUMBER':
-           val = int(val)
-         elif typ == 'HEXNUMBER':
-           val = int(val[2:], 16)
-           typ = 'NUMBER'
-         elif typ == 'REAL':
-           val = float(val)
-         elif typ == 'STRING':
-           val = val[1:-1]
-         yield Token(typ, val, line, mo.start()-line_start)
-       pos = mo.end()
-       mo = gettok(s, pos)
-     if pos != len(s):
-       col = pos - line_start
-       raise CompilerException('Unexpected character {0}'.format(s[pos]), line, col)
-     yield Token('END', '', line, 0)
-