lexer.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package lexer
  2. import "github/runnignwater/monkey/token"
  3. /**
  4. * @Author: simon
  5. * @Author: ynwdlxm@163.com
  6. * @Date: 2022/10/2 上午11:07
  7. * @Desc: ASCII 码
  8. */
  9. type Lexer struct {
  10. input string
  11. position int // current position in input (points to current char)
  12. readPosition int // current reading position in input (after current char)
  13. ch byte // current char under examination
  14. }
  15. func New(input string) *Lexer {
  16. l := &Lexer{input: input}
  17. l.readChar()
  18. return l
  19. }
  20. func (l *Lexer) readChar() {
  21. if l.readPosition >= len(l.input) {
  22. l.ch = 0
  23. } else {
  24. l.ch = l.input[l.readPosition]
  25. }
  26. l.position = l.readPosition
  27. l.readPosition += 1
  28. }
  29. /**
  30. * Only peek ahead in the input
  31. * and not move around in it
  32. */
  33. func (l *Lexer) peekChar() byte {
  34. if l.readPosition >= len(l.input) {
  35. return 0
  36. } else {
  37. return l.input[l.readPosition]
  38. }
  39. }
  40. func (l *Lexer) readIdentifier() string {
  41. position := l.position
  42. for isLetter(l.ch) {
  43. l.readChar()
  44. }
  45. return l.input[position:l.position]
  46. }
  47. func (l *Lexer) readNumber() string {
  48. position := l.position
  49. for isDigit(l.ch) {
  50. l.readChar()
  51. }
  52. return l.input[position:l.position]
  53. }
  54. func (l *Lexer) readString() string {
  55. position := l.position + 1
  56. for {
  57. l.readChar()
  58. if l.ch == '"' {
  59. break
  60. }
  61. }
  62. return l.input[position:l.position]
  63. }
  64. func (l *Lexer) NextToken() token.Token {
  65. var tok token.Token
  66. l.skipWhitespace()
  67. switch l.ch {
  68. case '=':
  69. if l.peekChar() == '=' {
  70. ch := l.ch
  71. l.readChar()
  72. tok = token.Token{Type: token.EQ, Literal: string(ch) + string(l.ch)}
  73. } else {
  74. tok = newToken(token.ASSIGN, l.ch)
  75. }
  76. case ';':
  77. tok = newToken(token.SEMICOLON, l.ch)
  78. case '(':
  79. tok = newToken(token.LPAREN, l.ch)
  80. case ')':
  81. tok = newToken(token.RPAREN, l.ch)
  82. case ',':
  83. tok = newToken(token.COMMA, l.ch)
  84. case '+':
  85. tok = newToken(token.PLUS, l.ch)
  86. case '-':
  87. tok = newToken(token.MINUS, l.ch)
  88. case '!':
  89. if l.peekChar() == '=' {
  90. ch := l.ch
  91. l.readChar()
  92. tok = token.Token{Type: token.NotEq, Literal: string(ch) + string(l.ch)}
  93. } else {
  94. tok = newToken(token.BANG, l.ch)
  95. }
  96. case '*':
  97. tok = newToken(token.ASTERISK, l.ch)
  98. case '/':
  99. tok = newToken(token.SLASH, l.ch)
  100. case '<':
  101. tok = newToken(token.LT, l.ch)
  102. case '>':
  103. tok = newToken(token.GT, l.ch)
  104. case '{':
  105. tok = newToken(token.LBRACE, l.ch)
  106. case '}':
  107. tok = newToken(token.RBRACE, l.ch)
  108. case '"':
  109. tok.Type = token.STRING
  110. tok.Literal = l.readString()
  111. case '[':
  112. tok = newToken(token.LBRACKET, l.ch)
  113. case ']':
  114. tok = newToken(token.RBRACKET, l.ch)
  115. case ':':
  116. tok = newToken(token.COLON, l.ch)
  117. case 0:
  118. tok.Type = token.EOF
  119. tok.Literal = ""
  120. default:
  121. if isLetter(l.ch) {
  122. tok.Literal = l.readIdentifier()
  123. tok.Type = token.LookupIdent(tok.Literal)
  124. } else if isDigit(l.ch) {
  125. tok.Type = token.INT
  126. tok.Literal = l.readNumber()
  127. } else {
  128. tok = newToken(token.ILLEGAL, l.ch)
  129. }
  130. return tok
  131. }
  132. l.readChar()
  133. return tok
  134. }
  135. func (l *Lexer) skipWhitespace() {
  136. for l.ch == ' ' || l.ch == '\t' || l.ch == '\n' || l.ch == '\r' {
  137. l.readChar()
  138. }
  139. }
  140. func isDigit(ch byte) bool {
  141. return '0' <= ch && ch <= '9'
  142. }
  143. func isLetter(ch byte) bool {
  144. return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_'
  145. }
  146. func newToken(tokenType token.TypeToken, ch byte) token.Token {
  147. return token.Token{Type: tokenType, Literal: string(ch)}
  148. }