You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
2.1 KiB

  1. package circuitcompiler
  2. import (
  3. "bufio"
  4. "bytes"
  5. "io"
  6. )
  7. type OperatorSymbol int
  8. type Token int
  9. const (
  10. ILLEGAL Token = iota
  11. WS
  12. EOF
  13. IDENT // val
  14. VAR // var
  15. CONST // const value
  16. EQ // =
  17. PLUS // +
  18. MINUS // -
  19. MULTIPLY // *
  20. DIVIDE // /
  21. EXP // ^
  22. OUT
  23. )
  24. var eof = rune(0)
  25. func isWhitespace(ch rune) bool {
  26. return ch == ' ' || ch == '\t' || ch == '\n'
  27. }
  28. func isLetter(ch rune) bool {
  29. return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
  30. }
  31. func isDigit(ch rune) bool {
  32. return (ch >= '0' && ch <= '9')
  33. }
  34. type Scanner struct {
  35. r *bufio.Reader
  36. }
  37. func NewScanner(r io.Reader) *Scanner {
  38. return &Scanner{r: bufio.NewReader(r)}
  39. }
  40. func (s *Scanner) read() rune {
  41. ch, _, err := s.r.ReadRune()
  42. if err != nil {
  43. return eof
  44. }
  45. return ch
  46. }
  47. func (s *Scanner) unread() {
  48. _ = s.r.UnreadRune()
  49. }
  50. func (s *Scanner) Scan() (tok Token, lit string) {
  51. ch := s.read()
  52. if isWhitespace(ch) {
  53. // space
  54. s.unread()
  55. return s.scanWhitespace()
  56. } else if isLetter(ch) {
  57. // letter
  58. s.unread()
  59. return s.scanIndent()
  60. } else if isDigit(ch) {
  61. s.unread()
  62. return s.scanIndent()
  63. }
  64. switch ch {
  65. case eof:
  66. return EOF, ""
  67. case '=':
  68. return EQ, "="
  69. case '+':
  70. return PLUS, "+"
  71. case '-':
  72. return MINUS, "-"
  73. case '*':
  74. return MULTIPLY, "*"
  75. case '/':
  76. return DIVIDE, "/"
  77. case '^':
  78. return EXP, "^"
  79. }
  80. return ILLEGAL, string(ch)
  81. }
  82. func (s *Scanner) scanWhitespace() (token Token, lit string) {
  83. var buf bytes.Buffer
  84. buf.WriteRune(s.read())
  85. for {
  86. if ch := s.read(); ch == eof {
  87. break
  88. } else if !isWhitespace(ch) {
  89. s.unread()
  90. break
  91. } else {
  92. _, _ = buf.WriteRune(ch)
  93. }
  94. }
  95. return WS, buf.String()
  96. }
  97. func (s *Scanner) scanIndent() (tok Token, lit string) {
  98. var buf bytes.Buffer
  99. buf.WriteRune(s.read())
  100. for {
  101. if ch := s.read(); ch == eof {
  102. break
  103. } else if !isLetter(ch) && !isDigit(ch) {
  104. s.unread()
  105. break
  106. } else {
  107. _, _ = buf.WriteRune(ch)
  108. }
  109. }
  110. switch buf.String() {
  111. case "var":
  112. return VAR, buf.String()
  113. }
  114. if len(buf.String()) == 1 {
  115. return Token(rune(buf.String()[0])), buf.String()
  116. }
  117. if buf.String() == "out" {
  118. return OUT, buf.String()
  119. }
  120. return IDENT, buf.String()
  121. }