Поєднання регулярних виразів для видалення деяких видів використання символу періоду

У мене є вихідні файли Fortran 77, які я намагаюся перетворити з нестандартного синтаксису STRUCTURE та RECORD в стандартний Fortran 90 TYPE синтаксис Один складний аспект цього полягає в різному способі розгляду членів структури.

Нестандартна:

s.member = 1

Стандарт:

s%member = 1

Отже, мені потрібно заманити всі періоди використання в подібних сценаріях і замінити їх символами % . Не дуже погано, крім випадків, коли ви думаєте про всі способи використання періодів (десяткові числа у цифрах, імена файлів в include statements, знаки пунктуації у коментарях, оператори зв'язку Fortran 77, а можливо, і інші). Я зробив деяку попередню обробку, щоб виправити реляційні оператори, щоб використовувати символи Fortran 90, і мені не дуже подобається граматика коментарів, але я не підібрав хороший підхід до перекладу . до % для описаних вище випадків. Схоже, я повинен мати можливість це зробити з седом, але я не знаю, як зіставлю ті випадки, які мені потрібно виправити. Ось правила, які я думав:

Послідовно:

  • If the line begins with include, then we shouldn't do anything to that line; pass it through to the output, so we don't mess up the filename inside the include statement.

  • The following strings are operators that don't have symbolic equivalents, so they must be left alone: .not. .and. .or. .eqv. .neqv.

  • Otherwise, if we find a period that is surrounded by 2 non-numeric characters (so it's not a decimal point), then it should be the operator that I'm looking to replace. Change that period to a %.

Я сам не рідний спікер Fortran, тому ось кілька прикладів:

include 'file.inc'        ! We don't want to do anything here. The line can
                          ! begin with some amount of whitespace

if x == 1 .or. y > 2.0    ! In this case, we don't want to touch the periods that
                          ! are part of the logical operator ".or.". We also don't
                          ! want to touch the period that is the decimal point 
                          ! in "2.0".
if a.member < 4.0 .and. b.othermember == 1.0 ! We don't want to touch the periods
                                             ! inside the numbers, but we need to
                                             ! change the "a." and "b." to "a%"
                                             ! and "b%".

Будь-який хороший спосіб вирішити цю проблему?

Edit: I actually found some additional operators that contain a dot in them that don't have symbolic equivalents. I've updated the rule list above.

4
@ Jonathan: Багато структур, багато полів, безліч вихідних файлів. Безумовно, це можливо зробити вручну, але, як інженер, я, за визначенням, ледачий.
додано Автор Jason R, джерело
@alexurba: Хороший момент. Я не думаю, що цей тип позначень використовується в цих файлах, і якщо він знаходиться в кількох місцях, то я зможу це виправити вручну після цього.
додано Автор Jason R, джерело
Наскільки великою є кодова база; n кількість файлів?
додано Автор Rook, джерело
Введення з усіма або декількома випадками було б непогано для користувачів, які не мають фортранс :)
додано Автор FailedDev, джерело
Скільки загальних "структур" ви маєте в цілому, і скільки полях вони мають колективно? Можливо найпростіше просто шукати \ .field1 і змінити на% field1 і т. Д.
додано Автор Jonathan Dursi, джерело
Не забудьте про . True. і .false. , і не забувайте, що Fortran не має зарезервованих слів, тому технічно змінні або елементи структури можуть бути названі включити , і , true тощо, що робить надзвичайно важким відмінність між ключовими словами та ідентифікаторами; очевидно, тому стандартний комітет пішов з % як розділювач-член, а не . . Зараз, щоб виписати код з такими ідентифікаторами, потрібно було б зовсім неправильному програмісту, але історія Fortran, на жаль, не повністю позбавлена ​​таких людей ;-).
додано Автор eriktous, джерело
О, і, звичайно ж, у фіксованому вигляді пробіл не є значним, тому, наприклад, включити може бути написано i n c l ude .
додано Автор eriktous, джерело
Назва змінної FORTRAN може містити номери, але оскільки перший символ має бути буквою, ви можете використовувати таке: \ w [a-zA-Z0-9 ()] {0,5} \. \ W
додано Автор Legogris, джерело
Майте на увазі, що числа з плаваючою точкою в Fortran також можуть виглядати як 1.e0 1.d0 ...
додано Автор alexurba, джерело

6 Відповіді

Ви не можете це зробити за допомогою регулярного виразу, і це не так просто.

Якщо мені довелося робити те, що вам потрібно, я, мабуть, зробив би це вручну, якщо кодове вікно не буде величезним. Якщо застосовуватись перше, спочатку замінити всі [a-zA-Z0-9]. [A-zA-Z] на щось дуже дивне, що гарантовано ніколи не складати, щось на кшталт "@ WHATEVER @", а потім перейти до пошуку всіх цих вводьте і замініть їх вручну після ручного керування.

Якщо кількість коду величезна, то вам потрібно написати аналізатор. Я б запропонував вам використовувати python для токенування базових конструкцій fortran, але пам'ятайте, що fortran не є простим для аналізу мовою. Працюйте "за звичайну", і спробуйте знайти всі імена змінних, використовуючи їх як фільтр. Якщо ви зіткнулися з чимось на зразок a.whatever , і ви знаєте, що a знаходиться в списку локальних або глобальних vars, застосуйте зміни.

2
додано
Я згоден, що це не просто, але у мене багато файлів. Я сподіваюся знайти рішення, що не потребує створення повнотекстового аналізатора мови. Ваша порада заміни дозорних значень може допомогти. Я можу звести всіх операторів (наприклад, ".and."), Спочатку замінюючи їх рядками, які я вважаю надзвичайно неймовірними, а потім повернути їх пізніше. Що залишилося б - виявлення періоду, оточеного символами, які, як видається, є дійсними для імен змін, які не повинні бути надто поганими. Це для моєї зручності, а не для будь-якої системи виробничого рівня, тому підходить підхід.
додано Автор Jason R, джерело
Шлях до вечірки пізніше, але: програмне забезпечення, подібне до деяких IDE, може шукати шаблон, перелічити всі результати і дозволити видалити ті, які ви не хочете замінити. Та ж ідея, але набагато легше. (Наприклад, IDE Jetbrains, насправді не має значення, що вони не для Fortran)
додано Автор Mark, джерело

Unless the codebase is really HUUGE (and do think very hard whether this is indeed the case), I'd just take an editor like Vim (vertical select & block select are your friends) a*nd set aside an afternoon to do this by hand*. In one afternoon, my guess is you'll be done with most of it, if not all. Afternoon is a lot of time. Just imagine how many cases you could've covered in these 2 hours alone.

Просто намагаючись написати аналізатор для чогось подібного, це займе значно більше часу.

Звичайно, питання благає себе ... якщо код, який F77, який всі компілятори все ще підтримують, і код працює ... чому ви так захочете змінити це?

2
додано
@ eriktous - усвідомлюючи це. Але справа в тому, що багато, що було розширенням постачальників в F77, тепер стандартно, а ті, які не підтримуються, і інші компілятори сьогодні.
додано Автор Rook, джерело
На останньому абзаці: цілком слід сказати, що код не є стандартним F77, але використовує специфічні розширення постачальників. Однак це може бути варто перевірити, чи дозволяють будь-які поточні компілятори цим розширенням.
додано Автор eriktous, джерело

Я не такий, що розбирається в регулярних виразах, тому я думаю, що спробую вирішити цю проблему з іншого боку. Якщо ви grep для ключового слова STRUCTURE , ви отримаєте список всіх кодів STRUCTURES . Після цього, для кожного STRUCTURE S ви можете просто замінити всі екземпляри S. на S% .

Таким чином, вам не потрібно турбуватися про такі речі, як . True. , .and , .neq та їх родичі. Основна турбота полягає в тому, щоб спробувати проаналізувати декларації STRUCTURE .

2
додано
так, точно з виводу grep STRUCTURE * .f (припускаючи, що це деякий * nix), не так важко отримати імена змінних, то для кожної з змінних це в основному grep variable-name .
додано Автор ev-br, джерело
Проблема з членами STRUCTURE. Тому спочатку треба шукати всі визначення STRUCTURE, а потім усі декларації змінних цього типу.
додано Автор alexurba, джерело

Виходячи з ваших прикладів, я гадаю, цього буде достатньо, щоб захистити цитовані рядки, а потім замінити періоди алфавітом з обох сторін.

perl -pe '1 while s%(\x27[^\x27]+)\.([^\x27]+\x27)%[email protected]@::@@$2%;
    s/([a-z])\.([a-z])/$1%$2/g;
    s/@@::@@/./g' file.f

Я пропоную цей Perl-рішення не тому, що sed не є достатньою для цього інструментом, але тому, що він уникає проблеми незначних, але болісних розбіжностей між sed dialects. Можливість використання шестнадцатого коду для одиночних лапок - приємний бонус.

0
додано

Цей седельний мережевий мозок може стати початком

sed -r '/^\s*include/b;/^\s*! /b;G;:a;s/^(\.(not|and|or|eqv|neqv)\.)(.*\n.*)/\3\1/;ta;s/^\.([^0-9]{2,})(.*\n.*)/\2%\1/;ta;s/^(.)(.*\n.*)/\2\1/;ta;s/\n//'
0
додано

Хоча регулярний вираз нижче:

(?

Replace $1%$2

Працює відмінно для ваших прикладів, я б не рекомендував використовувати його з поточним завданням. Це, безумовно, не охоплюватиме всі ваші справи. Тепер, якщо ви дбаєте про 80% покриття або щось, що ви могли б використати, але ви, можливо, повинні зробити резервну копію ваших джерел. З обмеженим набором випадків вхідних документів я переконався, що будуть випадки, коли регулярний вираз замінить те, що воно не повинно.

Удачі :)

0
додано