#lang racket

; parser for two binary operators that take strings as parameters
; s1 + s2 -> "(s1, s2)"
; s1 * s2 -> "[s1-s2]"

; grammar is (in this version, * is evaluated left-to-right, + right-to-left)
; <term> ::= <factor> | <term> * <factor>
; <factor> ::= <string> | <string> + <factor>

(define (plus s1 s2)
  (string-append "(" s1 ", " s2 ")"))

(define (times s1 s2)
  (string-append "[" s1 "-" s2 "]"))

(define (parse-term lst)
  (let* ([result1 (parse-factor lst)]
         [first (car result1)]
         [rest (cdr result1)])
    (if (and (pair? rest) (eq? (car rest) '*))
        (let* ([result2 (parse-factor (cdr rest))]
               [text (times first (car result2))])
          (parse-term (cons text (cdr result2))))
        result1)))

(define (parse-factor lst)
  (if (not (and (pair? lst) (string? (car lst))))
      (error "invalid syntax")
      (let ([first (car lst)]
            [rest (cdr lst)])
        (if (and (pair? rest) (eq? (car rest) '+))
            (let* ([result (parse-factor (cdr rest))]
                   [text (plus first (car result))])
              (cons text (cdr result)))
            lst))))

(define test1 '("a" + "b" + "c" + "d"))
(define test2 '("a" * "b" * "c" * "d"))
(define test3 '("a" + "b" * "c" * "d" + "e" * "f" * "g" + "h"))
; (parse-term test3) should return:
; [[[[(a, b)-c]-(d, e)]-f]-(g, h)]