Modify tokenizer to parse notes

This commit is contained in:
Bartłomiej Pluta
2019-07-05 18:36:12 +02:00
parent ad19e851ec
commit 425d23eb5f
9 changed files with 70 additions and 101 deletions

74
grammar
View File

@@ -1,42 +1,42 @@
integer := ...
string := ...
note := ...
identifier := ...
# Tokenizer
DIGIT = [0-9]
ID = [a-zA-Z_]
CHAR = ... \ '"'
PITCH = 'c' | 'd' | 'e' | 'f' | 'g' | 'a' | 'h'
PITCH_MODIFIER = 'b' | '#'
expr := integer
expr := string
expr := note
expr := identifier
expr := access
expr := assignment
expr := functionCall
integer := '-' DIGIT+ | DIGIT+
string := '"' CHAR* '"'
note := '@' PITCH PITCH_MODIFIER? DIGIT? ['.' DIGIT+ 'd'?]?
identifier := ID [ID|DIGIT]*
percent := DIGIT+ '%'
# left associative
access := expr '.' expr
# right associative
asterisk := expr '*' stmt
stmt := asterisk
stmt := block
stmt := return
stmt := functionDefinition
# right associative
assignment := identifier '=' expr
list := '(' ')'
list := '(' expr listTail
listTail := expr ', ' listTail
listTail := ')'
percent := integer '%'
return := 'return' expr
block := '{' stmt* '}'
# Parser
expr := integer accessTail | integer
expr := percent accessTail | percent
expr := string accessTail | string
expr := note accessTail | note
expr := identifier accessTail | identifier '=' expr | functionCall | identifier
expr := list accessTail | list
expr := functionCall accessTail | functionCall
functionCall := identifier list
functionDefinition := 'function' identifier list block
accessTail := '.' expr accessTail | e
list := '[' ']' | '[' expr listTail
listTail := expr ', ' listTail | ']'
argList := '(' ')' | '(' expr argListTail
argListTail := expr ', ' argListTail | ')'
block := '{' stmt* '}'
stmt := expr asteriskTail | expr #nie wiem czy zamiast 'expr asteriskTail' nie powinno być wprost co może wyprodukować iterator dla asterisk
asteriskTail := '*' stmt | e
stmt := block
stmt := 'return' expr
stmt := 'function' identifier list block
program := stmt*

View File

@@ -1,42 +0,0 @@
# Tokenizer
DIGIT = [0-9]
ID = [a-zA-Z_]
CHAR = ... \ '"'
PITCH = 'c' | 'd' | 'e' | 'f' | 'g' | 'a' | 'h'
PITCH_MODIFIER = 'b' | '#'
integer := '-' DIGIT+ | DIGIT+
string := '"' CHAR* '"'
note := '@' PITCH PITCH_MODIFIER? DIGIT? ['.' DIGIT+ 'd'?]?
identifier := ID [ID|DIGIT]*
percent := DIGIT+ '%'
# Parser
expr := integer accessTail | integer
expr := percent accessTail | percent
expr := string accessTail | string
expr := note accessTail | note
expr := identifier accessTail | identifier '=' expr | functionCall | identifier
expr := list accessTail | list
expr := functionCall accessTail | functionCall
functionCall := identifier list
accessTail := '.' expr accessTail | e
list := '[' ']' | '[' expr listTail
listTail := expr ', ' listTail | ']'
argList := '(' ')' | '(' expr argListTail
argListTail := expr ', ' argListTail | ')'
block := '{' stmt* '}'
stmt := expr asteriskTail | expr #nie wiem czy zamiast 'expr asteriskTail' nie powinno być wprost co może wyprodukować iterator dla asterisk
asteriskTail := '*' stmt | e
stmt := block
stmt := 'return' expr
stmt := 'function' identifier list block
program := stmt*

View File

@@ -1,7 +1,4 @@
from smnp.error.base import SmnpException
class NoteException(SmnpException):
class NoteException(Exception):
def __init__(self, msg):
super().__init__(msg)

View File

@@ -17,7 +17,7 @@ def main():
ast = Program.parse(tokens)
ast.node.print()
sys.exit(0)
env = createEnvironment()
evaluate(ast, env)

View File

@@ -1,7 +1,13 @@
from smnp.note.pitch import NotePitch
class Note:
def __init__(self, note, octave = 4, duration = 4, dot = False):
def __init__(self, note, octave, duration, dot = False):
if octave is None:
octave = 4
if duration is None:
duration = 4
if type(note) == str:
self.note = NotePitch.toPitch(note)
else:

0
smnp/note/note.py Normal file
View File

View File

@@ -47,6 +47,7 @@ class NotePitch(Enum):
raise NoteException(f"Note '{string}' does not exist")
stringToPitch = {
'cb': NotePitch.H,
'c': NotePitch.C,
'c#': NotePitch.CIS,
'db': NotePitch.CIS,

View File

@@ -4,7 +4,7 @@ class Token:
self.value = value
self.pos = pos
def __str__(self):
return "Token(" + str(self.type) + ", '" + self.value + "', " + str(self.pos) + ")"
return "Token(" + str(self.type) + ", '" + str(self.value) + "', " + str(self.pos) + ")"
def __repr__(self):
return self.__str__()

View File

@@ -1,37 +1,44 @@
import re
from smnp.token.type import TokenType
from smnp.note.model import Note
from smnp.token.model import Token
from smnp.token.type import TokenType
def tokenizeNote(input, current, line):
consumedChars = 0
value = ''
notePitch = None
octave = None
duration = None
dot = False
if input[current] == '@':
consumedChars += 1
value += input[current]
if input[current+consumedChars] in ('C', 'c', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'A', 'a', 'H', 'h', 'B', 'b'):
value += input[current+consumedChars]
notePitch = input[current+consumedChars]
consumedChars += 1
if current+consumedChars < len(input) and input[current+consumedChars] in ('b', '#'):
value += input[current+consumedChars]
notePitch += input[current+consumedChars]
consumedChars += 1
if current+consumedChars < len(input) and re.match(r'\d', input[current+consumedChars]):
value += input[current+consumedChars]
octave = input[current+consumedChars]
consumedChars += 1
if current+consumedChars < len(input) and input[current+consumedChars] == '.':
duration = input[current+consumedChars]
if current+consumedChars < len(input) and input[current+consumedChars] == '.':
duration = ''
consumedChars += 1
while current+consumedChars < len(input) and re.match(r'\d', input[current+consumedChars]):
duration += input[current+consumedChars]
consumedChars += 1
if current+consumedChars < len(input) and input[current+consumedChars] == 'd':
duration += input[current+consumedChars]
consumedChars += 1
if len(duration) > 1:
value += duration
else:
consumedChars -= 1
if len(duration) == 0:
return (0, None)
dot = (current+consumedChars) < len(input) and input[current+consumedChars] == 'd'
consumedChars += 1
octave = int(octave) if octave is not None else None
duration = int(duration) if duration is not None else None
value = Note(notePitch, octave, duration, dot)
return (consumedChars, Token(TokenType.NOTE, value, (line, current)))
return (0, None)