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.

132 lines
2.6 KiB

  1. package circuitcompiler
  2. import (
  3. "errors"
  4. "io"
  5. "regexp"
  6. "strings"
  7. )
  8. type Parser struct {
  9. s *Scanner
  10. buf struct {
  11. tok Token // last read token
  12. lit string // last read literal
  13. n int // buffer size (max=1)
  14. }
  15. }
  16. type Constraint struct {
  17. // v1 op v2 = out
  18. Op Token
  19. V1 string
  20. V2 string
  21. Out string
  22. Literal string
  23. Inputs []string // in func delcaration case
  24. }
  25. func NewParser(r io.Reader) *Parser {
  26. return &Parser{s: NewScanner(r)}
  27. }
  28. func (p *Parser) scan() (tok Token, lit string) {
  29. // if there is a token in the buffer return it
  30. if p.buf.n != 0 {
  31. p.buf.n = 0
  32. return p.buf.tok, p.buf.lit
  33. }
  34. tok, lit = p.s.Scan()
  35. p.buf.tok, p.buf.lit = tok, lit
  36. return
  37. }
  38. func (p *Parser) unscan() {
  39. p.buf.n = 1
  40. }
  41. func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) {
  42. tok, lit = p.scan()
  43. if tok == WS {
  44. tok, lit = p.scan()
  45. }
  46. return
  47. }
  48. func (p *Parser) ParseLine() (*Constraint, error) {
  49. /*
  50. in this version,
  51. line will be for example s3 = s1 * s4
  52. this is:
  53. val eq val op val
  54. */
  55. c := &Constraint{}
  56. tok, lit := p.scanIgnoreWhitespace()
  57. c.Out = lit
  58. c.Literal += lit
  59. if c.Literal == "func" {
  60. // format: `func name(in):`
  61. line, err := p.s.r.ReadString(':')
  62. if err != nil {
  63. return c, err
  64. }
  65. // read string inside ( )
  66. rgx := regexp.MustCompile(`\((.*?)\)`)
  67. insideParenthesis := rgx.FindStringSubmatch(line)
  68. varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
  69. c.Inputs = strings.Split(varsString, ",")
  70. return c, nil
  71. }
  72. _, lit = p.scanIgnoreWhitespace() // skip =
  73. c.Literal += lit
  74. // v1
  75. _, lit = p.scanIgnoreWhitespace()
  76. c.V1 = lit
  77. c.Literal += lit
  78. // operator
  79. c.Op, lit = p.scanIgnoreWhitespace()
  80. c.Literal += lit
  81. // v2
  82. _, lit = p.scanIgnoreWhitespace()
  83. c.V2 = lit
  84. c.Literal += lit
  85. if tok == EOF {
  86. return nil, errors.New("eof in parseline")
  87. }
  88. return c, nil
  89. }
  90. func addToArrayIfNotExist(arr []string, elem string) []string {
  91. for _, v := range arr {
  92. if v == elem {
  93. return arr
  94. }
  95. }
  96. arr = append(arr, elem)
  97. return arr
  98. }
  99. func (p *Parser) Parse() (*Circuit, error) {
  100. circuit := &Circuit{}
  101. circuit.Signals = append(circuit.Signals, "one")
  102. for {
  103. constraint, err := p.ParseLine()
  104. if err != nil {
  105. break
  106. }
  107. if constraint.Literal == "func" {
  108. circuit.Inputs = constraint.Inputs
  109. continue
  110. }
  111. circuit.Constraints = append(circuit.Constraints, *constraint)
  112. circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1)
  113. circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V2)
  114. circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.Out)
  115. }
  116. return circuit, nil
  117. }