Форум программистов, компьютерный форум, киберфорум
Haskell
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.73/11: Рейтинг темы: голосов - 11, средняя оценка - 4.73
165 / 164 / 23
Регистрация: 23.02.2011
Сообщений: 347

Инфикс -> Постфикс

27.10.2013, 13:41. Показов 2071. Ответов 3
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Мне необходимо распарсить математическое выражение и перевести выражение в постфикс для последующего вычисления на стековой машине. Я написал решение, но оно довольно некрасивое:
1) список лексем приобразуется в дерево, для избавления от скобок 1 + (2 - 3) * (sin x) -> [1,+,[[2,-,3],*,[sin, x]]]
2) дерево инфикс -> постфикс [1,+,[[2,-,3],*,[sin, x]]] -> [1,[[2,3,-],[x, sin],*],+]
3) раскрытие дерева в список [1,2,3,-,x,sin,*,+]
Три прохода для такой простой задачи некруто.
Может кто-нибудь подсказать мне более простое решение
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
data Lexem = Var String -- переменная
           | Val Double -- число 
           | Func1 (Double -> Double) -- функция 
           | Func2 (Double -> Double -> Double) -- оператор
--  using only in building
           | Bro -- "("
           | Brc -- ")"
           | Err -- флаг ошибки построения
           | Block [Lexem] -- используется при избавлении от скобок
 
{-
      после построения результата идет проверка, есть ли в результирующем списке лексема Err. Так происходит проверка на 
      корректность. Проверка на правильное количество скобок происходит до вызова toBlocks
-}
 
toBlocks :: [Lexem] -> [Lexem] -> ([Lexem],[Lexem])
toBlocks [] a = (reverse a,[])
toBlocks (Bro : t) acc = case toBlocks t [] of
                            (l,t') -> toBlocks t' (Block l : acc)
toBlocks (Brc : t) acc = (reverse acc,t)
toBlocks (h : t) acc = toBlocks t (h : acc)
 
toPostfix :: [Lexem] -> [Lexem] -> [Lexem]
toPostfix [] s = s
toPostfix (f@(Func2 _) : b : t) s' = case (b,s') of
                                        (Func1 _,_)     -> [Err]
                                        (Func2 _,_)     -> [Err]
                                        (Block b',a:s)  -> toPostfix t (Block [Block (toPostfix b' []),a,f] : s)
                                        (_,a:s)         -> toPostfix t (Block [b,a,f] : s)
                                        _               -> [Err]
toPostfix (f@(Func1 _) : a : t) s = case a of
                                        Func1 _ -> [Err]
                                        Func2 _ -> [Err]
                                        Block a' -> toPostfix t (Block [Block (toPostfix a' []), f] : s)
                                        _        -> toPostfix t (Block [a, f]: s)
toPostfix [Func1 _] _ = [Err]
toPostfix [Func2 _] _ = [Err]
toPostfix (Block l : t) s = toPostfix t (Block (toPostfix l []) : s)
toPostfix (v : t) s = toPostfix t (v : s)
 
toStack :: [Lexem] -> [Lexem]
toStack l = l >>= open
    where
        open a = case a of
                    Block [] -> [Err]
                    Block l -> l >>= open
                    _       -> [a]
 
-- для необработанного списка лексем 'list' используется так toStack (toPostfix (fst (toBlocks list [])) [])
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
27.10.2013, 13:41
Ответы с готовыми решениями:

Инфикс -> Постфикс
Здравствуйте! Уже неделю бьюсь над казалось бы простой задачей, нужно чтобы программа переводила инфиксную запись в постфиксную, то есть...

Из инфикс в постфикс
Вообщем есть задание написать клас в котором будет выражение переводиться в reversed polish notation. Вроде все написал все работает, но...

постфикс и префикс в c++
Почему получилось в последнем выводе car3.vivod -1 #include "stdafx.h" #include<iostream> using namespace std; class Cars ...

3
Супер-модератор
Эксперт функциональных языков программированияЭксперт Python
 Аватар для Catstail
38175 / 21110 / 4307
Регистрация: 12.02.2012
Сообщений: 34,712
Записей в блоге: 14
27.10.2013, 14:09
Цитата Сообщение от Algiz Посмотреть сообщение
Три прохода для такой простой задачи некруто.
Может кто-нибудь подсказать мне более простое решение
- а однопроходный алгоритм Замельзона (стек с приоритетами)?
1
Эксперт С++
 Аватар для Nameless One
5828 / 3479 / 358
Регистрация: 08.02.2010
Сообщений: 7,448
27.10.2013, 22:16
От второго прохода можно избавиться, если выполнить постфиксный обход (функция toRPN) дерева (Expr):
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import Control.Monad.Writer
 
type Name = String
 
data Expr = EVar Name
          | EConst Double
          | EApp Name Expr       -- допустим, что все функции унарные
          | EBinOp Name Expr Expr
            deriving Show
 
data RPNToken = Var Name
              | Const Double
              | App Name
              | BinOp Name
                deriving Show
 
type RPNStream = Writer [RPNToken] ()
 
infix2postfix :: Expr -> [RPNToken]
infix2postfix = execWriter . toRPN
 
toRPN :: Expr -> RPNStream
toRPN (EVar n)         = tell [Var n]
toRPN (EConst d)       = tell [Const d]
toRPN (EApp n e)       = toRPN e >> tell [App n]
toRPN (EBinOp n e1 e2) = toRPN e1 >> toRPN e2 >> tell [BinOp n]
 
testExpr :: Expr
testExpr = EBinOp "+"
                  (EConst 1.0)
                  (EBinOp "*"
                          (EBinOp "-"
                                  (EConst 2.0)
                                  (EConst 3.0))
                          (EApp "sin"
                                (EVar "x")))
Пример:
Haskell
1
2
> infix2postfix testExpr
[Const 1.0,Const 2.0,Const 3.0,BinOp "-",Var "x",App "sin",BinOp "*",BinOp "+"]
В общем случае: если выполнять инфиксный обход дерева выражений, то получим выражение в инфиксной форме, если префиксный — в префиксной, если постфиксный — в постфиксной.

Добавлено через 2 часа 31 минуту
Можно также строить выражение в постфиксной форме сразу на этапе парсинга по алгоритму http://en.wikipedia.org/wiki/S... _algorithm :
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import Text.Parsec hiding (token)
import Text.Parsec.Language (emptyDef)
import Text.Parsec.Token (float, makeTokenParser)
 
import Control.Monad.Writer
import Control.Monad.State
import Control.Monad.Identity
 
 
import Control.Applicative hiding (many, (<|>), Const)
 
import Data.Functor
 
type Name = String
 
data Token = TApp Name
           | TBinOp Name Priority Assoc
           | TParen
             deriving Show
 
data Assoc = AssocLeft
           | AssocRight
             deriving (Eq, Show)
 
type Priority = Int
 
data RPNToken = Var Name
              | Const Double
              | App Name
              | BinOp Name
                deriving Show
 
type Parser = ParsecT String () (WriterT [RPNToken] (StateT [Token] Identity))
 
push :: Token -> Parser ()
push t = modify (t :)
 
nil :: Parser Bool
nil = null <$> get
 
top :: Parser Token
top = do
  stack <- get
  case stack of
    []      -> fail "mismatched parenthesis"
    (s : _) -> return s
 
pop :: Parser Token
pop = top <* modify (tail)
 
out :: RPNToken -> Parser ()
out = lift . tell . (: [])
 
testParser p source = runIdentity (runStateT (runWriterT (runPT p () "(infix2postfix)" source)) [])
 
execParser :: Parser () -> String -> Either String [RPNToken]
execParser p source =
   case runIdentity (runStateT (runWriterT (runPT p () "(infix2postfix)" source)) []) of
    ((Left err, _), _)  -> Left $ show err
    ((Right _, out), s) ->
      case s of
        []        -> Right out
        _         -> loop s out
  where loop :: [Token] -> [RPNToken] -> Either String [RPNToken]
        loop [] out                  = Right out
        loop (TParen : _) _          = Left "mismatched parentheses"
        loop (TBinOp n _ _ : ss) out = loop ss (out ++ [BinOp n])
        loop (TApp n : ss) out       = loop ss (out ++ [App n])
 
token :: Parser a -> Parser a
token = between spaces spaces
 
reserved :: String -> Parser String
reserved = token . (<* notFollowedBy letter) . try . string
 
-- Беззнаковое вещественное число
floating :: Parser Double
floating = do
  int <- many1 digit
  fract <- option "" maybeFloat
  return $ read $ int ++ fract
      where maybeFloat =  char '.' >> ('.' : ) <$> many1 digit
 
 
constant :: Parser ()
constant = token $ Const <$> floating >>= out
 
op :: String -> Priority -> Assoc -> Parser ()
op n p a = do
  token $ string n
  loop
  push $ TBinOp n p a
      where loop = do
              isEmpty <- nil
              unless isEmpty $ do
                t <- top
                case t of
                  TBinOp n' p' a' ->
                    when ((a == AssocLeft && p == p') || (p < p')) $ do
                      pop
                      out $ (BinOp n')
                      loop
                  _ -> return ()
 
fun :: String -> Parser ()
fun name = token $ do
  reserved name
  push (TApp name)
 
lparen :: Parser ()
lparen = token (char '(') >> push TParen
 
rparen :: Parser ()
rparen = do
  token (char ')')
  loop
      where loop = do
              t <- pop
              case t of
                TParen       -> do
                  t' <- top
                  case t' of
                    TApp n -> pop >> out (App n)
                    _      -> return ()
                TBinOp n _ _ -> do
                  out $ BinOp n
                  loop
                TApp n       -> do
                  out $ App n
                  loop
 
var :: Parser ()
var = token $ many1 letter >>= out . Var
 
tok :: Parser ()
tok = constant
  <|> fun "sin"
  <|> fun "cos"
  <|> var
  <|> lparen
  <|> rparen
  <|> op "-" 1 AssocLeft
  <|> op "+" 1 AssocLeft
  <|> op "*" 2 AssocLeft
  <|> op "^" 3 AssocRight
 
expr :: Parser ()
expr = skipMany1 tok *> eof
Haskell
1
2
> execParser expr "1 + (2 - 3) * sin (x)"
Right [Const 1.0,Const 2.0,Const 3.0,BinOp "-",Var "x",App "sin",BinOp "*",BinOp "+"]
Однако стоит учитывать, что в таком случае не будут корректно обрабатываться ошибки; для этого нужно построить нормальный парсер, но вместо дерева строить выражение в RPN.

Добавлено через 1 час 27 минут
Цитата Сообщение от Nameless One Посмотреть сообщение
для этого нужно построить нормальный парсер, но вместо дерева строить выражение в RPN.
Например, вот так (пожалуй, это самый лучший вариант)
Haskell
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import Text.Parsec hiding (token)
import Control.Applicative hiding (many, (<|>), Const)
import Data.Functor
import Data.List (intercalate)
 
type Name = String
type Priority = Int
 
data RPNToken = Var Name
              | Const Double
              | App Name
              | BinOp Name
                deriving Show
 
type Parser = Parsec String ()
type Arity = Int
 
token :: Parser a -> Parser a
token = between spaces spaces
 
reserved :: String -> Parser String
reserved = try . token . (<* notFollowedBy letter) . string
 
floating :: Parser Double
floating = do
  int <- many1 digit
  fract <- option "" maybeFloat
  return $ read $ int ++ fract
      where maybeFloat =  char '.' >> ('.' : ) <$> many1 digit
 
constant :: Parser RPNToken
constant = Const <$> token floating <?> "floating constant"
 
var :: Parser RPNToken
var = Var <$> token (many1 letter) <?> "variable"
 
binOp :: String -> Parser ([RPNToken] -> [RPNToken] -> [RPNToken])
binOp n = do
  op <- BinOp <$> try (token (string n)) <?> "binary operator " ++ n
  return $ \o1 o2 -> o1 ++ o2 ++ [op]
 
lparen, rparen :: Parser Char
lparen = token (char '(') <?> "left parenthesis"
rparen = token (char ')') <?> "right parenthesis"
 
parens :: Parser a -> Parser a
parens = between lparen rparen
 
factor :: Parser [RPNToken]
factor = parens expr
     <|> functions
     <|> (: []) <$> var
     <|> (: []) <$> constant
 
functions :: Parser [RPNToken]
functions = fun "sin" 1
        <|> fun "cos" 1
        <|> fun "max" 2
        <|> fun "min" 2
 
arguments :: Arity -> Parser [RPNToken]
arguments 0 = return []
arguments 1 = expr
arguments n = (++) <$> expr <* comma <*> arguments (n - 1)
 
comma :: Parser Char
comma = token (char ',') <?> "comma"
 
fun :: String -> Arity -> Parser [RPNToken]
fun name n = do
  f <- App <$> token (reserved name) <?> "function " ++ name ++ "(" ++ args ++ ")"
  args <- parens $ arguments n
  return $ args ++ [f]
      where args = intercalate ", " $ map (("x" ++ ) . show) [1..n]
 
term :: Parser [RPNToken]
term = factor `chainl1` mulOp
 
expr :: Parser [RPNToken]
expr = term `chainl1` addOp
 
mulOp, addOp :: Parser ([RPNToken] -> [RPNToken] -> [RPNToken])
mulOp = binOp "*"
 
addOp = binOp "-"
    <|> binOp "+"
 
parser :: Parser [RPNToken]
parser = expr <* eof
Помимо прочего, парсер поддерживает n-арные функции с проверкой арности функции на этапе разбора (т.к. отдельной стадии семантического анализа тут, по-видимому, не требуется):
Haskell
1
2
> parseTest parser "1 + (2 - max(3, min(4, 5))) * sin(4) * cos(4)"
[Const 1.0,Const 2.0,Const 3.0,Const 4.0,Const 5.0,App "min",App "max",BinOp "-",Const 4.0,App "sin",BinOp "*",Const 4.0,App "cos",BinOp "*",BinOp "+"]
1
165 / 164 / 23
Регистрация: 23.02.2011
Сообщений: 347
27.10.2013, 22:19  [ТС]
Спасибо, буду пробовать Замельзона
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
27.10.2013, 22:19
Помогаю со студенческими работами здесь

Префикс и постфикс
практически только начал изучать С# дошел до префиксов и постфиксов, я понял что это переменная +\- 1 и пишутся например ++а\а++ но не могу...

постфикс полей в таблицах БД
Привет ребята. Подскажите пожалуйста (извиняюсь если не там создала тему). В vs2010 есть Server Explorer у меня там содержится 20 таблиц и...

Постфикс списка на прологе
доброго времени суток :) как получить постфикс списка?смог сделать только префикс: prefix(_, ). prefix(, ) :-prefix(H1, H2). ...

Постфикс в префикс, используя цикл или рекурсию
Скажите пожалуйста можно ли сделать программку конвертер с постфикса в префикс используя только цикл или рекурсию, без стэка и без дерева?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru