Реализация C подобной программы в ракетке с использованием lex / yacc - PullRequest
0 голосов
/ 22 апреля 2020

Я смотрел на эти два ресурса (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

1 Ответ

1 голос
/ 22 апреля 2020

Вы не можете легко реализовать язык с условными и циклическими конструкциями, используя оценщик, основанный на немедленной оценке.

Это должно быть понятно по крайней мере для циклов. Если у вас есть что-то вроде (с использованием супер-упрощенного синтаксиса):

repeat 3 { i = i + 1 }

Если вы оцениваете во время анализа, i = i + 1 будет оцениваться ровно один раз, так как строка анализируется ровно один раз. Чтобы его можно было оценивать несколько раз, анализатору необходимо преобразовать i = i + 1 во что-то, что можно оценивать несколько раз при оценке repeat.

Обычно это что-то вроде Абстрактный синтаксис Дерево (AST) или, возможно, список операций на виртуальной машине . С помощью Scheme вы также можете просто превратить анализируемое выражение в функционал.

Все это абсолютно практично и даже не особенно сложно, но вам нужно быть готовым к чтению, как о разборе, так и о генерации исполняемых файлов. Для последнего я настоятельно рекомендую classi c Структура и интерпретация компьютерных программ (Abelson & Sussman) .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...