2008-09-22 27 views
52

Jaki jest najmądrzejszy sposób zaprojektowania parsera matematycznego? Mam na myśli funkcję, która pobiera ciąg matematyczny (np. "2 + 3/2 + (2 * 5)") i zwraca obliczoną wartość? Napisałem jeden w VB6 przed wiekami, ale okazało się, że jest to droga do nadęcia i niezbyt przenośnego (lub mądrego o to chodzi ...). Ogólne pomysły, kod psuedo lub prawdziwy kod są mile widziane.Inteligentny projekt analizatora matematycznego?

+0

możesz wypróbować implementację algorytmu manewrowego dla java tutaj: http://projects.congrace.de/exp4j/ – fasseg

+0

Sprawdź kod, który opublikowałem w https://stackoverflow.com/questions/28256/equation- wyrażenie-parser-z-pierwszeństwem/46722767 # 46722767 – user4617883

+0

Sprawdź kod, który opublikowałem w https://stackoverflow.com/questions/28256/equation-expression-parser-with-precedence/46722767#46722767 – user4617883

Odpowiedz

76

Całkiem dobre podejście wymagałoby dwóch kroków. Pierwszy etap obejmuje notację converting the expression from infix to postfix (na przykład poprzez Dijkstra's shunting yard). Gdy to zrobisz, napisanie postfix evaluator jest dość banalne.

+0

Nie sądzę Algorytm manewrowania stoczniowego może obsłużyć prawidłowe jednoargumentowe połączenie ujemne z podstawami wykładników. tj. nie może parsować -2^3 jako - (2^3), tylko jako (-2)^3. Mogę się mylić, nie wiem na pewno. – chbaker0

+0

@mebob To wygląda na błąd wprowadzany przeze mnie przez użytkownika. Nie zadałbym sobie trudu, żeby to poprawić. Jeśli czułam się dobrze, mógłbym dodać coś, żeby to sprawdzić i ostrzec użytkownika, że ​​mogą być w błędzie. – Yay295

5

Masz kilka podejść. Można wygenerować kod dynamiczny i wykonać go, aby uzyskać odpowiedź bez potrzeby pisania zbyt wielu kodów. Po prostu wyszukaj kod wygenerowany w środowisku wykonawczym w .NET i znajdziesz mnóstwo przykładów.

Alternatywnie można utworzyć rzeczywisty analizator składni i wygenerować małe drzewo analizy, które jest następnie używane do oceny wyrażenia. Znowu jest to bardzo proste dla podstawowych wyrażeń. Sprawdź kodek, bo uważam, że mają tam parser matematyczny. Lub poszukaj BNF, który będzie zawierał przykłady. Każda strona internetowa wprowadzająca koncepcje kompilacji będzie to traktować jako podstawowy przykład.

Codeplex Expression Evaluator

1

Zakładając, że wejście jest wyrazem infix w formacie strun, można przekonwertować go do postfix i wykorzystując parę stosów: stosu operatora i stosu argumentu, praca rozwiązanie stamtąd. Możesz znaleźć ogólne informacje o algorytmie w linku do Wikipedii.

4

Jeśli masz aplikację "zawsze włączona", po prostu dodaj ciąg matematyczny do google i przeanalizuj wynik. Prosty sposób, ale nie jestem pewien, czy to jest to, czego potrzebujesz - ale w pewien sposób sprytny.

+2

Nie, niezbyt inteligentny. Ale "załatwia sprawy". –

+2

To znaczy, że jesteś na tyle mądry, żeby wiedzieć, jak załatwić sprawy ;-) – JRoppert

1

ANTLR to bardzo ładny generator parseli LL (*). Polecam to bardzo.

3

Wiem, że to jest stare, ale natknąłem się na tę próbę opracowania kalkulatora jako części większej aplikacji i napotkano pewne problemy przy użyciu zaakceptowanej odpowiedzi. Linki były NIEZWYKLE pomocne w zrozumieniu i rozwiązaniu tego problemu i nie powinny być dyskontowane. Pisałem aplikację na Androida w Javie i dla każdego elementu w wyrażeniu "ciąg" faktycznie zapisałem ciąg w tablicy ArrayList, gdy użytkownik wpisuje klawiaturę. W przypadku konwersji infiks-postfix wykonałem iterację za pomocą każdego ciągu w tablicy ArrayList, a następnie przeanalizowałem nowo uporządkowaną tabelę Postfiksów ArrayList ciągów. Było to fantastyczne dla niewielkiej liczby operandów/operatorów, ale dłuższe obliczenia były konsekwentnie wyłączone, zwłaszcza gdy wyrażenia rozpoczęły się od wartości nie będących liczbami całkowitymi. W podanym łączu dla Infix to Postfix conversion sugeruje pojawienie się stosu, jeśli zeskanowany element jest operatorem, a element topStack ma wyższy priorytet. Stwierdziłem, że to prawie poprawne. Popping topStack item, jeśli jest wyższy priorytet LUB RÓWNOWAGA dla zeskanowanego operatora w końcu sprawił, że moje obliczenia wypadły poprawnie. Mam nadzieję, że to pomoże każdemu, kto pracuje nad tym problemem, a dzięki Justinowi Polieyowi (i fas?) Za dostarczenie nieocenionych linków.

1

Programiści zawsze chcą mieć czyste podejście i spróbuj wdrożyć logikę parsowania od podstaw, zwykle kończąc na Dijkstra Shunting-Yard Algorithm. Rezultatem jest zgrabnie wyglądający kod, ale możliwe, że jest on również zainfekowany błędami. Opracowałem taki API, JMEP, który robi to wszystko, ale utrzymanie stabilnego kodu zajęło mi lata.

Nawet przy całej tej pracy można zobaczyć nawet z tej strony projektu, którą poważnie rozważam, aby przełączyć na używanie JavaCC lub ANTLR, nawet po wykonaniu wszystkich tych prac.