Advertisement
Guest User

Untitled

a guest
Nov 9th, 2022
48
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Nim 3.99 KB | None | 0 0
  1. import std/[strutils, strformat]
  2. import token
  3.  
  4. # Reserved words in the lexer
  5. const reservedWords = @["if", "else", "then", "do", "for", "function", "while", "end"]
  6.  
  7. ## Lexer state machine object
  8. type Lexer* = object
  9.     src*: string
  10.     prevPos: int
  11.     currPos: int
  12.     line: int
  13.  
  14.     tokens: seq[Token]
  15.  
  16. func initLexer*(src: string): Lexer = Lexer(src: src, prevPos: 0, currPos: 0)
  17. func atEnd(lexer: Lexer, offset = 0): bool = lexer.currPos + offset >= lexer.src.len
  18.  
  19. # Helpers
  20. func isReserved(word: string): bool =
  21.     if word in reservedWords:
  22.         result = true
  23.  
  24. func advance(lexer: var Lexer): char =
  25.     if not lexer.atEnd(0):
  26.         result = lexer.src[lexer.currPos + 1]
  27.         lexer.currPos += 1
  28.  
  29. func peek(lexer: Lexer): char =
  30.     if not lexer.atEnd(0):
  31.         result = lexer.src[lexer.currPos + 1]
  32.  
  33. func addToken(lexer: var Lexer, tk: TokenKind) =
  34.     lexer.tokens.add(Token(kind: tk, start: lexer.prevPos, endAt: lexer.currPos))
  35.  
  36. # Lexer rules
  37. proc scanIdent(lexer: var Lexer) =
  38.     while lexer.peek.isAlphaNumeric or lexer.peek == '_':
  39.         discard lexer.advance()
  40.    
  41.     var tokenKind: TokenKind
  42.     let ident = lexer.src.substr(lexer.prevPos, lexer.currPos - lexer.prevPos)
  43.     if ident.isReserved:
  44.         tokenKind = case ident
  45.             of "if": tkIF
  46.             of "else": tkELSE
  47.             of "then": tkTHEN
  48.             of "do": tkDO
  49.             of "for": tkFOR
  50.             of "function": tkFUNCTION
  51.             of "while": tkWHILE
  52.             of "end": tkEND
  53.             else: tkIDENT
  54.        
  55.     lexer.addToken(tokenKind)
  56.  
  57. proc scanString(lexer: var Lexer) =
  58.     while lexer.peek != '"' and not lexer.atEnd:
  59.        discard lexer.advance()
  60.    
  61.    if lexer.atEnd:
  62.        let ln = lexer.line
  63.        echo(fmt"Unterminated string literal (at {lexer.prevPos}:{lexer.currPos}, L{ln})")
  64.  
  65.    # Closing quote
  66.    discard lexer.advance()
  67.  
  68.    let slice = lexer.src.substr(lexer.prevPos, lexer.currPos - lexer.prevPos)
  69.    echo(fmt"String slice: {slice}")
  70.    lexer.addToken(tkSTRING)
  71.  
  72. proc scanInt(lexer: var Lexer) =
  73.    while lexer.peek.isDigit:
  74.        discard lexer.advance()
  75.  
  76.    if lexer.peek == '.' and lexer.advance.isDigit:
  77.        while lexer.peek.isDigit:
  78.            discard lexer.advance()
  79.  
  80.    let slice = lexer.src.substr(lexer.prevPos, lexer.currPos - lexer.prevPos)
  81.    echo(fmt"Integer slice: {slice}")
  82.    lexer.addToken(tkINT)
  83.  
  84. ##
  85. ## Scan the source string and return a sequence of tokens
  86. ##
  87. proc scan*(lexer: var Lexer): seq[Token] =
  88.    var c: char
  89.    while not lexer.atEnd:
  90.        lexer.prevPos = lexer.currPos
  91.        c = lexer.advance()
  92.        
  93.        echo(c)
  94.  
  95.        case c:
  96.        of '"': lexer.scanString
  97.         of '(': lexer.addToken(tkLPAREN)
  98.         of ')': lexer.addToken(tkRPAREN)
  99.         of '+': lexer.addToken(tkPLUS)
  100.         of '-':
  101.             if lexer.peek == '-':
  102.                 # Comment
  103.                 discard
  104.             else: lexer.addToken(tkMINUS)
  105.         of '*': lexer.addToken(tkSTAR)
  106.         of '/': lexer.addToken(tkSLASH)
  107.         of '=':
  108.             if lexer.peek == '=':
  109.                 lexer.addToken(tkDEQUAL)
  110.             else: lexer.addToken(tkEQUAL)
  111.         of '<':
  112.             if lexer.peek == '=':
  113.                 lexer.addToken(tkLT_EQUAL)
  114.             else: lexer.addToken(tkLESS)
  115.         of '>':
  116.             if lexer.peek == '=':
  117.                 lexer.addToken(tkGT_EQUAL)
  118.             else: lexer.addToken(tkGREAT)
  119.         of '!':
  120.             if lexer.peek == '=':
  121.                 lexer.addToken(tkNEQUAL)
  122.             else: lexer.addToken(tkNOT)
  123.         of '\r', '\t':
  124.             discard
  125.         of '\n':
  126.             lexer.line += 1
  127.         of '\0':
  128.             if lexer.atEnd: break
  129.         else:
  130.             if c.isAlphaAscii or c == '_':
  131.                 lexer.scanIdent()
  132.             elif c.isDigit:
  133.                 lexer.scanInt()
  134.             else:
  135.                 echo(fmt"Unexpected character '{c}'")
  136.  
  137.     result = lexer.tokens
  138.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement