Я смотрел на эти два ресурса (https://github.com/racket/parser-tools/blob/master/parser-tools-lib/parser-tools/examples/calc.rkt и https://gist.github.com/gcr/1318240) и хотя пока не до конца понимаю, как работает основная функция cal c, я Интересно, возможно ли расширить это, чтобы работать для простой c подобной программы просто без функций? Так что он будет лексировать, анализировать и оценивать ifs, whiles и печатать операторы. Итак, что-то вроде (define-empty-tokens op-tokens ( newline = OC CC (open-curly/closed-curly for block statements) DEL PRINT WHILE (WHILE exp S) S IF S1 S2 (IF exp S1 S2) OP CP + - * / || % or && == != >= <= > < EOF ))
Вот как я расширил его (код первой ссылки) для работы с логическими значениями:
Итак, в calcl я добавил эти две строки :
[ (:= 2 #\|) (token-||)]
[(:or "=" "+" "-" "*" "/" "%" "&&" "==" "!=" ">=" "<=" ">" "<") (string->symbol lexeme)]
А потом позже:
(define calcp
(parser
(start start)
(end newline EOF)
(tokens value-tokens op-tokens)
(error (lambda (a b c) (void)))
(precs (right =)
(left ||)
(left &&)
(left == !=)
(left <= >= < >)
(left - +)
(left * / %)
)
(grammar
(start [() #f]
[(error start) $2]
[(exp) $1])
(exp [(NUM) $1]
[(VAR) (hash-ref vars $1 (lambda () 0))]
[(VAR = exp) (begin (hash-set! vars $1 $3)
$3)]
[(exp || exp) (if (not(and (equal? $1 0) (equal? $3 0) )) 1 0) ]
[(exp && exp) (and $1 $3)]
[(exp == exp) (equal? $1 $3)]
[(exp != exp) (not(equal? $1 $3))]
[(exp < exp) (< $1 $3)]
[(exp > exp) (> $1 $3)]
[(exp >= exp) (>= $1 $3)]
[(exp <= exp) (<= $1 $3)]
[(exp + exp) (+ $1 $3)]
[(exp - exp) (- $1 $3)]
[(exp * exp) (* $1 $3)]
[(exp / exp) (/ $1 $3)]
[(exp % exp) (remainder $1 $3)]
[(OP exp CP) $2]))))
Но я изо всех сил пытаюсь понять приведенный выше код, а также приведенный ниже. Я хотел бы изменить его, чтобы он также работал для ifs и whiles et c. если это вообще возможно?
(define (calc ip)
(port-count-lines! ip)
(letrec ((one-line
(lambda ()
(let ((result (calcp (lambda () (calcl ip)) )))
(when result (printf "~a\n" result) (one-line))
)
) ))
(one-line))
)
Кроме того, этот парень, кажется, полагается на символы новой строки, чтобы отметить конец утверждения. то есть вы не можете иметь более 1 оператора в одной строке. Я хочу, чтобы программа распознала два оператора в одной строке и оценила их отдельно, каким-то образом заглядывая в будущее и проверяя, есть ли новая необъявленная переменная, специальное ключевое слово или открытая / закрытая скобка и т. Д. c.
Обновление:
Мне удалось, используя приведенные ниже правила, встроить хвастовство AST для арифметических выражений, но как мне избавиться от всего, кроме важных слов, чтобы я мог оценить его?
Например: со списком ввода: (list (token 'NUM 17) '+ (token 'NUM 1) '* (token 'NUM 3) '/ 'OP (token 'NUM 6) '- (token 'NUM 5) 'CP)
Я возвращаюсь:
'(exp (((((factor 17)))) + (((((factor 1))) * ((factor 3))) / ((((((factor 6)))) - (((factor 5))))))))
Вот мои правила:
exp : add
/add : add ('+' mul)+ | add ('-' mul)+ | mul
/mul : mul ('*' atom)+ | mul ('/' atom)+ | mul ('%' atom)+ | atom
/atom : /OP add /CP | factor
factor : NUM | ID