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.

147 lines
2.3 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' || ch == '\r' || ch == '\v' || ch == '\f'
  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. // Scanner holds the bufio.Reader
  35. type Scanner struct {
  36. r *bufio.Reader
  37. }
  38. // NewScanner creates a new Scanner with the given io.Reader
  39. func NewScanner(r io.Reader) *Scanner {
  40. return &Scanner{r: bufio.NewReader(r)}
  41. }
  42. func (s *Scanner) read() rune {
  43. ch, _, err := s.r.ReadRune()
  44. if err != nil {
  45. return eof
  46. }
  47. return ch
  48. }
  49. func (s *Scanner) unread() {
  50. _ = s.r.UnreadRune()
  51. }
  52. // Scan returns the Token and literal string of the current value
  53. func (s *Scanner) scan() (tok Token, lit string) {
  54. ch := s.read()
  55. if isWhitespace(ch) {
  56. // space
  57. s.unread()
  58. return s.scanWhitespace()
  59. } else if isLetter(ch) {
  60. // letter
  61. s.unread()
  62. return s.scanIndent()
  63. } else if isDigit(ch) {
  64. s.unread()
  65. return s.scanIndent()
  66. }
  67. switch ch {
  68. case eof:
  69. return EOF, ""
  70. case '=':
  71. return EQ, "="
  72. case '+':
  73. return PLUS, "+"
  74. case '-':
  75. return MINUS, "-"
  76. case '*':
  77. return MULTIPLY, "*"
  78. case '/':
  79. return DIVIDE, "/"
  80. case '^':
  81. return EXP, "^"
  82. }
  83. return ILLEGAL, string(ch)
  84. }
  85. func (s *Scanner) scanWhitespace() (token Token, lit string) {
  86. var buf bytes.Buffer
  87. buf.WriteRune(s.read())
  88. for {
  89. if ch := s.read(); ch == eof {
  90. break
  91. } else if !isWhitespace(ch) {
  92. s.unread()
  93. break
  94. } else {
  95. _, _ = buf.WriteRune(ch)
  96. }
  97. }
  98. return WS, buf.String()
  99. }
  100. func (s *Scanner) scanIndent() (tok Token, lit string) {
  101. var buf bytes.Buffer
  102. buf.WriteRune(s.read())
  103. for {
  104. if ch := s.read(); ch == eof {
  105. break
  106. } else if !isLetter(ch) && !isDigit(ch) {
  107. s.unread()
  108. break
  109. } else {
  110. _, _ = buf.WriteRune(ch)
  111. }
  112. }
  113. switch buf.String() {
  114. case "var":
  115. return VAR, buf.String()
  116. }
  117. if len(buf.String()) == 1 {
  118. return Token(rune(buf.String()[0])), buf.String()
  119. }
  120. if buf.String() == "out" {
  121. return OUT, buf.String()
  122. }
  123. return IDENT, buf.String()
  124. }