1

I'm new in sly and I'm trying to write simple language with sly python. I want to implement if-else, while loop and print command. I tried to search a lot, but there aren't many tutorials about sly. I'm totally confused how can I make it.

I want something like that:

If-else statement:

a = 0
if (a == 0) then {
print "variable a is equal to zero"
...
} else {
print "variable a is not equal to zero"
...
}

While loop:

a = 0
while (a == 0) then {
a = a + 1
}

Print command:

print "hello world"

I found that code on https://sly.readthedocs.io/en/latest/sly.html with statements, but this is just lexer.

# calclex.py

from sly import Lexer

class CalcLexer(Lexer):
    # Set of token names.   This is always required
    tokens = { NUMBER, ID, WHILE, IF, ELSE, PRINT,
               PLUS, MINUS, TIMES, DIVIDE, ASSIGN,
               EQ, LT, LE, GT, GE, NE }


    literals = { '(', ')', '{', '}', ';' }

    # String containing ignored characters
    ignore = ' \t'

    # Regular expression rules for tokens
    PLUS    = r'\+'
    MINUS   = r'-'
    TIMES   = r'\*'
    DIVIDE  = r'/'
    EQ      = r'=='
    ASSIGN  = r'='
    LE      = r'<='
    LT      = r'<'
    GE      = r'>='
    GT      = r'>'
    NE      = r'!='

    @_(r'\d+')
    def NUMBER(self, t):
        t.value = int(t.value)
        return t

    # Identifiers and keywords
    ID = r'[a-zA-Z_][a-zA-Z0-9_]*'
    ID['if'] = IF
    ID['else'] = ELSE
    ID['while'] = WHILE
    ID['print'] = PRINT

    ignore_comment = r'\#.*'

    # Line number tracking
    @_(r'\n+')
    def ignore_newline(self, t):
        self.lineno += t.value.count('\n')

    def error(self, t):
        print('Line %d: Bad character %r' % (self.lineno, t.value[0]))
        self.index += 1

if __name__ == '__main__':
    data = '''
# Counting
x = 0;
while (x < 10) {
    print x:
    x = x + 1;
}
'''
    lexer = CalcLexer()
    for tok in lexer.tokenize(data):
        print(tok)

Hope you can help me.

Jurakin
  • 832
  • 1
  • 5
  • 19

1 Answers1

1

You can learn a lot of how to construct these basic things by following the examples for Ply, Sly's predecessor. I am going to assume that you're attempting to build an Abstract Syntax Tree (AST) from which you will generate (or interpret) the actual runtime code. I'll start with the print statement (this assumes you also have a STRING token, of course):

@_('PRINT STRING')
def print_statement(self, p):
    return ('PRINT', p.STRING)

This creates an AST tuple that you can interpret for printing. Next is a fairly simple one, the While statement:

@_('WHILE ( expression ) { statement_set }')
def while_statement(self, p):
    return ('WHILE', p.expression, p.statement_set)

Much like before, this creates a simple tuple that contains the command you wish to run ,'WHILE', the expression that will be tested, and the statement_set that will run. Note that, due to how Sly works, the expression and statement_set are their own non-terminals, and might include complex code including nested statements.

The If-else statement is slightly more complex because we have two situations, either an If statement without an else, and one with. For the sake of simplicity, we'll assume we always generate the same tuple of ('IF', expression, primary statementes, else statements).

@_('IF ( expression ) { statement_set }')
def if_statement(self, p):
    return ('IF', p.expression, p.statement_set, [])

@_('IF ( expression ) { statement_set } ELSE { statement_set }')
def if_statement(self, p):
    return ('IF', p.expression, p.statement_set0, p.statement_set1)

Of course, you will need to define the expression and statement_set non-terminals, but I'll assume you've already done some work there.

Sean Duggan
  • 1,105
  • 2
  • 18
  • 48