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.

185 lines
2.9 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 = 1 << iota
  11. WS
  12. EOF
  13. FUNC
  14. IDENT // val
  15. IN
  16. VAR // var
  17. CONST // const value
  18. EQ // =
  19. PLUS // +
  20. MINUS // -
  21. MULTIPLY // *
  22. DIVIDE // /
  23. EXP // ^
  24. OUT
  25. )
  26. func (ch Token) String() string {
  27. switch ch {
  28. case EQ:
  29. return "="
  30. case PLUS:
  31. return "+"
  32. case MINUS:
  33. return "-"
  34. case MULTIPLY:
  35. return "*"
  36. case DIVIDE:
  37. return "/"
  38. case EXP:
  39. return "^"
  40. case FUNC:
  41. return "def"
  42. case IN:
  43. return "In"
  44. case CONST:
  45. return "Const"
  46. default:
  47. return "unknown Token"
  48. }
  49. }
  50. var eof = rune(0)
  51. func isWhitespace(ch rune) bool {
  52. return ch == ' ' || ch == '\t' || ch == '\n'
  53. }
  54. func isLetter(ch rune) bool {
  55. return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
  56. }
  57. func isDigit(ch rune) bool {
  58. return (ch >= '0' && ch <= '9')
  59. }
  60. // Scanner holds the bufio.Reader
  61. type Scanner struct {
  62. r *bufio.Reader
  63. }
  64. // NewScanner creates a new Scanner with the given io.Reader
  65. func NewScanner(r io.Reader) *Scanner {
  66. return &Scanner{r: bufio.NewReader(r)}
  67. }
  68. func (s *Scanner) read() rune {
  69. ch, _, err := s.r.ReadRune()
  70. if err != nil {
  71. return eof
  72. }
  73. return ch
  74. }
  75. func (s *Scanner) unread() {
  76. _ = s.r.UnreadRune()
  77. }
  78. // Scan returns the Token and literal string of the current value
  79. func (s *Scanner) scan() (tok Token, lit string) {
  80. ch := s.read()
  81. if isWhitespace(ch) {
  82. // space
  83. s.unread()
  84. return s.scanWhitespace()
  85. } else if isLetter(ch) {
  86. // letter
  87. s.unread()
  88. return s.scanIndent()
  89. } else if isDigit(ch) {
  90. s.unread()
  91. return s.scanIndent()
  92. }
  93. switch ch {
  94. case eof:
  95. return EOF, ""
  96. case '=':
  97. return EQ, "="
  98. case '+':
  99. return PLUS, "+"
  100. case '-':
  101. return MINUS, "-"
  102. case '*':
  103. return MULTIPLY, "*"
  104. case '/':
  105. return DIVIDE, "/"
  106. case '^':
  107. return EXP, "^"
  108. //case '(':
  109. // return EXP, "func"
  110. }
  111. return ILLEGAL, string(ch)
  112. }
  113. func (s *Scanner) scanWhitespace() (token Token, lit string) {
  114. var buf bytes.Buffer
  115. buf.WriteRune(s.read())
  116. for {
  117. if ch := s.read(); ch == eof {
  118. break
  119. } else if !isWhitespace(ch) {
  120. s.unread()
  121. break
  122. } else {
  123. _, _ = buf.WriteRune(ch)
  124. }
  125. }
  126. return WS, buf.String()
  127. }
  128. func (s *Scanner) scanIndent() (tok Token, lit string) {
  129. var buf bytes.Buffer
  130. buf.WriteRune(s.read())
  131. tok = IDENT
  132. for {
  133. if ch := s.read(); ch == eof {
  134. break
  135. } else if ch == '(' {
  136. tok = FUNC
  137. _, _ = buf.WriteRune(ch)
  138. } else if ch == ',' && tok == FUNC {
  139. _, _ = buf.WriteRune(ch)
  140. } else if isWhitespace(ch) && tok == FUNC {
  141. continue
  142. } else if ch == ')' && tok == FUNC {
  143. _, _ = buf.WriteRune(ch)
  144. break
  145. } else if !isLetter(ch) && !isDigit(ch) {
  146. s.unread()
  147. break
  148. } else {
  149. _, _ = buf.WriteRune(ch)
  150. }
  151. }
  152. switch buf.String() {
  153. case "var":
  154. return VAR, buf.String()
  155. }
  156. if len(buf.String()) == 1 {
  157. return Token(rune(buf.String()[0])), buf.String()
  158. }
  159. if buf.String() == "out" {
  160. return OUT, buf.String()
  161. }
  162. return IDENT, buf.String()
  163. }