2016-07-29 30 views
5

Tôi đã cố gắng giải quyết vấn đề bằng trình kết hợp trình phân tích cú pháp. Tôi thử như sau:lập trình chức năng: hiểu trình phân tích cú pháp phân tích

Note: mã dưới đây sử dụng combinator library

styleParserItalic : Bool -> Parser (List (List Char , Style)) 
styleParserItalic bolded = 
let 
style = if bolded then Italic else Unstyled 
in 
(end `andThen` always ( succeed ([]))) 
<|> (string "(!ITALIC!)" `andThen` \_ -> styleParserItalic (not bolded) ) 
<|> (anyChar `andThen` \c -> styleParserItalic bolded `andThen` \cs -> succeed ((c :: [],style) :: cs)) 

Tôi đang đấu tranh để hiểu làm thế nào phân tích cú pháp này chạy kể từ khi phân tích cú pháp styleParserItalic được gọi trước khi phân tích cú pháp thành công.

Ai đó có thể giải thích cách trình phân tích cú pháp hoạt động khi nó được cung cấp một chuỗi ký tự?

Nếu ai đó quan tâm đến mục đích của trình phân tích cú pháp và mã đầy đủ, here là câu hỏi trước của tôi.

Dưới đây là những gì tôi đã hiểu vậy, đến nay

Các phân tích cú pháp sẽ kiểm tra đầu tiên nếu nó là kết thúc của một dòng, nếu không nó sẽ cố gắng phân tích cú pháp chuỗi (!ITALIC!) nếu đó là trường hợp sau đó nó sẽ gọi trình phân tích cú pháp với tham số True hoặc false (nếu false thì sẽ làm cho nó đúng ..)

Nếu trình phân tích cú pháp không tìm thấy chuỗi (! ITALIC!) nó sẽ phân tích cú pháp bất kỳ ký tự nào, nó sẽ gọi trình phân tích cú pháp lần nữa.

Điều gây nhầm lẫn cho tôi là trình phân tích cú pháp sẽ tiếp tục gọi chính nó miễn là nó thành công với việc phân tích cú pháp bất kỳ ký tự nào!

chỉnh sửa: *LƯU Ý CÁC DƯỚI ĐÂY LÀ KHÔNG PHẢI LÀ MỘT PHẦN CỦA CÂU HỎI, chỉ để chia sẻ mã NẾU AI ĐÓ LÀ QUAN TÂM

nhờ cho tất cả các câu trả lời, tôi đã cập nhật các phân tích cú pháp để phân tích gạch dưới nghiêng Bold ..., theo ảnh chụp màn hình dưới đây enter image description here

type Style = Bold| Unstyled | Italic | Coded | Lined | Titled | Marked  | Underline 

styleParser : Bool ->Bool ->Bool ->Bool-> Bool-> Bool->Bool 
           -> Parser (List (List Char ,  (Style,Style,Style,Style,Style,Style,Style))) 
           --(bold,italic ,code,line ,Titled,mark) 
styleParser bolded italiced coded lined titled marked underlined= 
    let 
    style = (
    if bolded  then Bold  else Unstyled 
    ,if italiced then Italic else Unstyled 
    ,if coded  then Coded  else Unstyled 
    ,if lined  then Lined  else Unstyled 
    ,if titled  then Titled else Unstyled 
    ,if marked  then Marked else Unstyled 
    ,if underlined then Underline else Unstyled 
    ) 
    in 
    (end `andThen` always (succeed ([]))) 
    <|> (string "//" `andThen` \_ -> styleParser bolded  italiced   coded  lined  titled  marked  (not underlined)) 
    <|> (string "**" `andThen` \_ -> styleParser (not bolded) italiced  coded  lined  titled  marked  underlined) 
    <|> (string "*" `andThen` \_ -> styleParser bolded  (not italiced) coded  lined  titled  marked  underlined) 
    <|> (string "`" `andThen` \_ -> styleParser bolded  italiced  (not coded) lined  titled  marked  underlined) 
    <|> (string "/br" `andThen` \_ -> styleParser bolded  italiced  coded  (not lined) titled  marked  underlined) 
    <|> (string "/*" `andThen` \_ -> styleParser bolded  italiced  coded  lined  (not titled) marked  underlined) 
    <|> (string "{-" `andThen` \_ -> styleParser bolded  italiced  coded  lined  titled  (not marked) underlined) 
    <|> (anyChar  `andThen` \c -> styleParser bolded  italiced   coded  lined  titled  marked  underlined `andThen` \cs -> succeed ((c :: [],style) :: cs)) 


foldStyleHtml : List (List Char , ( Style,Style,Style,Style,Style,Style,Style)) -> List (Html Msg) 
foldStyleHtml lst = 
    List.map styleToHtml lst 


styleToHtml : (List Char, (Style ,Style,Style,Style,Style,Style,Style)) -> Html Msg 
styleToHtml (a,b) = 
    case b of 
    (Bold,Italic,_,_,_,_,Unstyled)  -> strong [] [em [][ text (String.fromList a)]] 
    (Bold,Italic,_,_,_,_,Underline)  -> u[][ strong [] [em [][ text (String.fromList a)]]] 
    (Bold,Unstyled,_,_,_,_,Underline) -> u[][ strong [] [text (String.fromList a)]] 
    (Unstyled,Italic,_,_,_,_,Underline) -> u[][ em  [] [text (String.fromList a)]] 
(Unstyled,Italic,_,_,_,_,_)   -> em[] [text (String.fromList a)] 
(Bold,Unstyled,_,_,_,_,_)   -> strong [][ text (String.fromList a)] 
(_,_,Coded,_,_,_,_)     -> code [codeStyle ][text  (String.fromList a)] 
(_,_,_,Lined,_,_,_)     -> br [][text " "] 
    -- (_,_,_,_,Titled,_,_)     -> div [][text (String.fromList a)] 
    (_,_,_,_,_,Marked,_)     -> mark [][text (String.fromList a)] 
    (_,_,_,_,_,_,Underline)    -> u [][text (String.fromList a)] 
    (_,_,_,_,_,_,_)      -> text (String.fromList a) 

htmlParser : Parser (List (Html Msg)) 
htmlParser = 
styleParser False False False False False False False `andThen` (succeed << foldStyleHtml) 

runParser : Parser (List (Html Msg)) -> String -> Html Msg 
runParser parser str         = 
    case parse parser str of 
    (Ok htmls,_)-> div [] htmls 
    (Err err, _) -> div [ style [("color", "red")] ] [ text <| toString <| err] 
+1

Tôi khiêm nhường sẽ đề cập đến [một bài blot Tôi đã viết một vài năm trước đây] (https://oldfashionedsoftware.com/2008/08/16/easy-parsing-in-scala /) dưới dạng giới thiệu về các trình kết hợp phân tích cú pháp. –

Trả lời

3

Bộ phối hợp phân tích (thường) tiêu thụ đầu vào khi chúng thành công. Trong thư viện này, nếu string "(!ITALIC!)" không thành công, nó sẽ không tiêu thụ bất kỳ đầu vào nào. Vì bộ phối hợp <|> được sử dụng, sau đó nó cố gắng sử dụng phần tiếp theo của mã bắt đầu bằng anyChar.

Khi anyChar thành công, nó tiêu thụ một ký tự đơn lẻ và chụp nó trong c sau andThen. Sau đó, chuỗi còn lại (mọi thứ nhưng ký tự được chụp bởi anyChar) sau đó được "thu thập thông tin" khi cuộc gọi đệ quy đến styleParserItalic bolded được thực hiện. Thứ hai andThen ghi lại đầu ra của bộ kết hợp đệ quy vào cs và thêm các ký tự đã được ghi vào phần còn lại của danh sách các ký tự từ cuộc gọi đệ quy.

Tôi nghĩ rằng phần quan trọng cần nhớ là các bộ kết hợp tiêu thụ đầu vào khi chúng thành công và (thường) không tiêu thụ đầu vào khi chúng không thành công.

+0

Cảm ơn, cứ mỗi lần gọi cho stylePurserItalic đệ quy, nó sẽ chuyển kết quả của nó tới cs và chạy trình phân tích cú pháp thành công hoặc nó sẽ đợi tất cả cuộc gọi đệ quy để kết thúc (tất cả ký tự được phân tích cú pháp) sau đó sẽ phân tích kết quả thành cs? –

+1

Vì nó đệ quy, nó sẽ recurse đến ký tự cuối cùng của chuỗi trước khi trở về chuỗi. Đó là lý do tại sao có bộ kết hợp đầu tiên của 'end', kiểm tra kết thúc của đầu vào và trả về danh sách rỗng nếu phù hợp (không có' kết thúc' nó sẽ quay mãi mãi). Cây đệ quy sau đó gấp và dựng lên danh sách bằng cách thêm mỗi 'c' vào' cs' được trả về từ cuộc gọi đệ quy. –

+0

cho phép nói rằng tôi đang cố gắng phân tích cú pháp chuỗi "ABC", kết quả cuối cùng sẽ thành công (('A', Unstyled) :: (B, Unstyled) :: (C, Unstyled) :: luôn (thành công ([]))) đúng ? Vì vậy, làm thế nào luôn luôn (thành công ([])) được thêm vào một danh sách các bộ dữ liệu? –

2

Trước tiên, một vài đơn giản ...

(1) Mỗi phần tử của danh sách bên trong chữ ký:

styleParserItalic : Bool -> Parser (List (List Char , Style)) 
              ^^^^^^^^^ 

chỉ là một nhân vật duy nhất. Chỉ cần xóa :: [] khỏi dòng cuối cùng,

<|> ... `andThen` \cs -> succeed ((c ,style) :: cs)) 
            ^^^ 
             removed `:: []` 

bạn có thể đặt chữ ký này.

(2) Lưu ý rằng đối số bolded chỉ ảnh hưởng đến Kiểu - nó không ảnh hưởng đến luồng điều khiển. Nó thực sự nên được gọi là italic vì kiểu xuất hiện trong đầu ra là Italic nếu đối số là True và Unstyled nếu không.

Cũng lưu ý rằng khi thông số này được đặt là True, thông số này sẽ giữ nguyên trong tất cả các cuộc gọi đệ quy tiếp theo.

Vì vậy, bây giờ là thuật toán là:

  1. Nếu ở phần cuối của đường, trả lại danh sách trống.
  2. Nếu tại (!ITALIC!), hãy sử dụng Italic cho kiểu trong phần còn lại của phân tích cú pháp.
  3. Nếu không, phân tích cú pháp một ký tự, phân tích phần còn lại của dòng và nối các kết quả.

Một thuật toán xấp xỉ Python sẽ là một cái gì đó như:

def parseLine(style, line): 
    result = [] 
    while line: 
    if line.startsWith('(!ITALIC!)'): 
     line = line[8:] 
     style = Italic 
     # loop around 
    else: 
     result.append((line[0], style)) 
     line = line[1:] 
    return result 
Các vấn đề liên quan