Компиляторное
Feb. 10th, 2010 06:39 pmКто-то из мэтров, вроде Хейлсберга, говорил, что сложность развития компиляторов квадратичная: если уже есть N фич и нужно добавить еще одну, приходится продумывать и аккуратно реализовывать взаимодействие новой фичи со всеми N старыми. Не берусь пока это подтвердить или опровергнуть, но в моем случае добавление в Leo структур привело к серьезному рефакторингу модулей Leo и LeoC: косяки исходной реализации стали выпирать и мешаться слишком сильно, пришлось исправлять. В итоге общий размер исходников увеличился всего на 7 строк: небольшой рост модулей парсинга и LeoC был компенсирован заметным сокращением и упрощением модуля Leo в ходе рефакторинга.
Структуры мне нужны для более удобного взаимодействия кода на Leo с кодом программы-хоста. Выглядит это так:
В процессе тестирования всплыла очень смешная ошибка: описанный тут метод разбора делал арифметические операции правоассоциативными, в результате чего выражение 3 - 1 - 1 разбиралось как 3 - (1 - 1). Получилось так в ходе борьбы с левой рекурсией в грамматике, правило для сумм и разностей выглядело как
Структуры мне нужны для более удобного взаимодействия кода на Leo с кодом программы-хоста. Выглядит это так:
type point = { x : int; y : int } type indata = { len : int str : byte[len] # кстати, это похоже на частный случай зависимых типов ;) ints : int[10] p : point out : byte[len] } args : indata args.p.x <- 50; args.p.y <- 60 for i in args.ints.range args.ints[i] <- i+1 end for i in args.str.range args.out[i] <- args.str[|args.str| - 1 - i] endargs - имя входного параметра программы на Leo (наподобие argc и argv).
В процессе тестирования всплыла очень смешная ошибка: описанный тут метод разбора делал арифметические операции правоассоциативными, в результате чего выражение 3 - 1 - 1 разбиралось как 3 - (1 - 1). Получилось так в ходе борьбы с левой рекурсией в грамматике, правило для сумм и разностей выглядело как
E = P + E | P - E | PЕсли поменять местами P и E, ассоциативность станет нормальной, но возникнет левая рекурсия, что недопустимо. Проблема была решена путем преобразования таких правил в форму
E = P (+ P | - P)*Что в коде выглядит как:
and expr_r s = ( product >>= fun e1 -> p_seq0 ((tok Lplus >>> product >>= fun e2 -> return (Add, e2)) ||| (tok Lminus >>> product >>= fun e2 -> return (Sub, e2))) >>= fun ps -> return (List.fold_left (fun e1 (op, e2) -> Leo.Arith(op, e1, e2)) e1 ps) ) sАналогично для делений с умножениями.
Дальше: оптимизация.