Пріоритетність функції в алгоритмі Шунтування


10

Я працюю за алгоритмом « Шунтинг-двір» , як описано у wikipedia.

Опис алгоритму при роботі з операторами такий:

Якщо маркер є оператором, o1, то:

в той час як у верхній частині стека оператора є маркер оператора, o2, і будь-який

o1 is left-associative and its precedence is less than or equal to
that of o2, or

o1 is right associative, and has precedence less than that of o2,

потім вискочіть o2 зі стека операторів на вихідну чергу;

натисніть o1 на стек оператора.

Однак вони наводять такий приклад:

Вхід: sin max 2 3 / 3 * 3.1415

Коли алгоритм потрапляє на /маркер, опис того, що має відбутися, виглядає наступним чином:

Token |        Action       |   Output (in RPN) |   Operator Stack
...
/     | Pop token to output | 2 3 max           | / sin 
...

Вони спливають функцію токена maxвід stackі вводять вqueue . Згідно з їх алгоритмом, мабуть, це означає, що маркер функції є і оператором, і має пріоритет менше, ніж у /оператора.

Немає пояснень, чи так це чи ні. Отже, для Shunting-yardалгоритму, який пріоритет функції? Праві чи ліві асоціативні функції? Або Вікіпедія просто неповна / неточна?

Відповіді:


5

Я вважаю, що пряма відповідь полягає в тому, що функції - це не оператори. На сторінці, яку ви пов’язали:

Якщо маркер - це функція, то натисніть на стек.

Це все, що потрібно сказати, оскільки випадок функції (префікс до постфіксу) набагато простіший, ніж випадок оператора (інфікс до постфікса).

Для наступних питань: Поняття пріоритетності та асоціативності потрібні лише через неоднозначність спадку в будь-якому виразі з кількома операторами інфікування. Функціональні маркери вже використовують позначення префіксів, тому у них просто немає такої проблеми. Вам не потрібно знати , є чи sinабо maxмає «високий пріоритет» , щоб з'ясувати , що maxпотрібно оцінювати в першу чергу; це вже зрозуміло з порядку жетонів. Ось чому комп'ютери віддають перевагу позначення pre / postfix для початку, і чому у нас є цей алгоритм перетворення інфіксів у pre / postfix.

Вам потрібно мати якесь правило, де аргументи функції починаються та закінчуються, коли немає дужок, так що ви можете сказати, що функції "мають перевагу" над операторами або навпаки. Але на відміну від infix-операторів, одного єдиного послідовного правила для всіх функцій достатньо, щоб зробити їх композиції абсолютно однозначними.


Тоді їх алгоритм правильний; це їх приклад, який є невірним. Позначення інфіксації повинно включати в себе дужки, що обгортають функції:sin( max( 2 3) / 3 * 3.1415)
MirroredFate

Я не впевнений, чи вважаю я його неправильним, але це вагомий аргумент на користь мов, які вимагають дужок і косів навколо всіх функцій викликів.
Іксрек

Я думаю, що це неправильно, оскільки неможливо проаналізувати інфікс за допомогою алгоритму, який вони описують.
MirroredFate

@Ixrec Я не бачу рядка "Якщо маркер - це маркер функції, тоді натисніть на стек." на сторінці Вікіпедії. Може бути відредаговано на даний момент. Але ви маєте на увазі, що я можу трактувати функцію так само, як число в алгоритмі?
Абхінав

Я вважаю, в описі алгоритму в статті Вікіпедії (до сьогодні) є помилка. Після фрази if there is a left parenthesis at the top of the operator stack, then: pop the operator from the operator stack and discard itслід додати ще один рядок: якщо вгорі стека є ім’я функції, тоді виведіть її зі стека та натисніть на вихід . Іншими словами, ліворуч "(" завжди повинно з'являтися разом із назвою функції, якщо вони розміщені разом, як випливає з синтаксису функції: " name(".
Стент,

3

Можна розглянути два різні випадки, залежно від вашого синтаксису мови. Якщо ваша мова використовує дужки для позначення програми функції (наприклад f(2+1)), то пріоритет не має значення. Функцію слід висунути на стек і вискакувати після (наприклад, приклад вище 2 1 + f). Крім того, ви можете розглядати функцію як значення та негайно виводити її та виводити операцію виклику функції після закриття дужок (яка в іншому випадку повинна трактуватися так само, як і будь-які інші дужки), наприклад f 2 1 + $, де $операція виклику функції.

Якщо ваша мова не використовує дужки для позначення виклику функції, а замість цього розміщує аргумент безпосередньо після функції без будь-яких спеціальних пунктуацій (наприклад f 2 + 1), як це, мабуть, стосується прикладу Вікіпедії, тоді справи дещо складніші. Зауважте, що вираз, який я щойно наводив у прикладі, неоднозначний: f застосовується до 2 і 1 додається до результату, або ми додаємо 2 і 1 разом, а потім називаємо f результатом?

Знову ж таки, є два підходи. Ви можете просто натиснути функцію на стек операторів, коли ви зіткнетесь з нею та призначите їй будь-який пріоритет. Це найпростіший підхід і, мабуть, те, що було зроблено в наведеному прикладі. Однак є практичні питання. По-перше, як визначити функцію? Якщо у вас є обмежений набір, це легко, але якщо у вас визначені користувачем функції, це означає, що ваш парсер повинен занадто швидко повертатися у ваше оточення, яке може швидко заплутатися. І як ви обробляєте функції з кількома аргументами?

Моє відчуття полягає в тому, що для цього стилю синтаксису використання функцій як значень, зручніших оператором додатків функції, має набагато більше сенсу. Тоді ви можете просто ввести оператор програми кожен раз, коли ви читаєте значення, і останнє, що ви прочитали, також було значенням, тому вам не потрібен якийсь спеціальний спосіб вказувати, які ідентифікатори є функціями. Ви також можете працювати з виразами, які повертають функції (що складно або неможливо зі стилем функції як функціонування). А це означає, що ви можете використовувати currying для обробки декількох функцій аргументів, що є масовим спрощенням над спробами керувати ними безпосередньо.

Єдине, що вам потрібно вирішити, - це пріоритет застосування функції. Вибір вирішувати вам, але в кожній мові, яку я використовував, працює так, це був найбільш сильно зобов’язуючий оператор у мові та був правильним асоціативним. (Єдиним цікавим варіантом є Haskell, який, окрім того, що має описану сильно зв'язуючу версію, також має синонім до цього символу, $який є найбільш слабко зв'язуючим оператором у мові, що дозволяє виразам, як f 2 + 1застосовувати f до 2, так і f $ 2 + 1застосовувати це до всього решти виразу)


3

Я реалізував запитувані "функції в маневровому дворі", прочитавши оригінальне мислення Дійкстри (Сторінки 7-11 у папері компілятора Algol 60, https://ir.cwi.nl/pub/9251 ), і потребую надійного рішення, я зробив наступне:

розбір:

  • Натисніть дескриптор функції
  • Висуньте ліву дужку старту аргументу "[" так само, як і його скобки в наддепресії.
  • Прочитайте послідовність списку врівноважених аргументів "(" до ") з вхідних даних
  • Натисніть це на потік вихідного маркера
  • Натисніть правий кронштейн кінця дуги "]" так само, як і його "компенсуюча дужка закриття"

Інфіксація до постфіксу (маневровий двір):

  • Додайте ще один стек, стек функцій, як і стек операторів
  • Під час сканування імені функції натисніть інформацію про функцію до групи функцій
  • Коли видно праву дужку в кінці аргументів, виведіть стек функцій для виведення

Чудово працює в надійних тестуваннях і складних сценаріях. У своїй програмі (аргументи командного рядка, що містять вирази, що містять вирази), я підтримую функції декількох аргументів і знак ",", щоб розділити їх, і вони проходять через весь процес.

Приклади виглядають як "sqrt (3 ^ 2 + 4 ^ 2)", який стає "3 2 ^ 4 2 ^ + sqrt" і в кінцевому підсумку "5" - це те, що програма вважає аргументом. Це bignum, тому "" двочлен (64, 32) / gcd (двочлен (64, 32), двочлен (63, 31)) "==> великі речі ==>" 2 "є корисним." 123456 ^ 789 " становить 40 173 цифри, і час показує "оцінка = 0,000390 сек" на моєму MacBookPro, так швидко.

Я також використовую це для розширення даних у таблицях і знаходжу це зручно. У будь-якому випадку, це моя порада щодо мого обережного поводження з функціональними викликами, численними аргументами та глибоким вкладанням у контексті маневрових дворів Дійкстри. Щойно це зробили сьогодні з незалежного мислення. Не знаю, чи можуть бути кращі способи.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.