2009-08-22 17 views
9

Tôi đang cố gắng tìm hiểu BNF và cố gắng lắp ráp một số mã ASM Z80. Vì tôi mới làm quen với cả hai lĩnh vực, câu hỏi của tôi là, tôi có đi đúng hướng không? Tôi đang cố gắng để viết định dạng của Z80 ASM như EBNF để tôi có thể sau đó tìm ra nơi để đi từ đó để tạo ra mã máy từ nguồn. Tại thời điểm này, tôi có những điều sau đây:Cấu trúc ZF ASM BNF ... Tôi có đi đúng hướng không?

Assignment = Identifier, ":" ; 

Instruction = Opcode, [ Operand ], [ Operand ] ; 

Operand = Identifier | Something* ; 

Something* = "(" , Identifier, ")" ; 

Identifier = Alpha, { Numeric | Alpha } ; 

Opcode = Alpha, Alpha ; 

Int = [ "-" ], Numeric, { Numeric } ; 

Alpha = "A" | "B" | "C" | "D" | "E" | "F" | 
     "G" | "H" | "I" | "J" | "K" | "L" | 
     "M" | "N" | "O" | "P" | "Q" | "R" | 
     "S" | "T" | "U" | "V" | "W" | "X" | 
     "Y" | "Z" ; 

Numeric = "0" | "1" | "2" | "3"| "4" | 
      "5" | "6" | "7" | "8" | "9" ; 

Bất kỳ phản hồi định hướng nào nếu tôi sai sẽ là tuyệt vời.

+0

Ngắt của http://stackoverflow.com/questions/1305091/writing-an-z80-assembler-lexi ng-asm-và-xây dựng-một-parse-tree-sử dụng-sáng tác bởi cùng một người dùng –

+3

@Butterworth: không trùng lặp. Một câu hỏi khác liên quan đến việc truyền thông tin xung quanh bất kỳ cây nào mà anh ta có thể xây dựng bằng cách sử dụng một ngữ pháp. Câu hỏi này liên quan đến việc anh ta có nên sử dụng ngữ pháp hay không, và nếu có, nó sẽ như thế nào. Câu trả lời cho câu hỏi này là điều kiện tiên quyết cho câu hỏi khác là thú vị. –

Trả lời

16

Máy lắp ráp trường học cũ thường được mã hóa bằng tay trong bộ lắp ráp và sử dụng kỹ thuật phân tích cú pháp adhoc để xử lý các dòng nguồn lắp ráp để tạo mã lắp ráp thực. Khi cú pháp của trình biên dịch đơn giản (ví dụ: luôn luôn là OPCODE REG, OPERAND), điều này đã làm việc đủ tốt.

Máy hiện đại có bộ chỉ dẫn lộn xộn, khó chịu với nhiều biến thể lệnh và toán hạng, có thể được biểu diễn bằng cú pháp phức tạp cho phép nhiều thanh ghi chỉ mục tham gia biểu thức toán hạng. Cho phép các biểu thức thời gian lắp ráp phức tạp với các hằng số cố định và relocatable với các loại toán tử bổ sung khác nhau làm phức tạp điều này. Các trình tạo phức tạp cho phép biên dịch có điều kiện, các macro, các khai báo dữ liệu có cấu trúc, v.v. tất cả thêm các yêu cầu mới về cú pháp. Việc xử lý tất cả cú pháp này bằng các phương thức đặc biệt là rất khó và là lý do mà các trình tạo trình phân tích cú pháp được phát minh ra.

Sử dụng máy phát BNF và trình phân tích cú pháp là cách rất hợp lý để xây dựng bộ lắp ráp hiện đại, ngay cả đối với bộ xử lý cũ như Z80. Tôi đã xây dựng các bộ ghép như vậy cho các máy tính 8 bit của Motorola như 6800/6809 và đang sẵn sàng làm tương tự cho một máy x86 hiện đại. Tôi nghĩ bạn đang đi đúng hướng.

********** CHỈNH SỬA **************** OP hỏi các định nghĩa lexer và phân tích cú pháp ví dụ. Tôi đã cung cấp cả hai ở đây.

Đây là những trích đoạn từ thông số kỹ thuật thực sự cho một trình sao chép 6809. Các định nghĩa đầy đủ là 2-3x kích thước của các mẫu ở đây.

Để giảm dung lượng, tôi đã chỉnh sửa nhiều phần phức tạp ở góc tối là điểm của các định nghĩa này. Người ta có thể bị mất tinh thần bởi sự phức tạp của người lập; các điểm là với các định nghĩa như vậy, bạn đang cố gắng để mô tả hình dạng của ngôn ngữ, chứ không phải mã theo ngôn ngữ. Bạn sẽ phải trả mức độ phức tạp cao hơn đáng kể nếu bạn mã tất cả điều này theo cách đặc biệt và sẽ còn xa hơn ít bảo trì hơn.

Nó cũng sẽ giúp đỡ một số khi biết rằng những định nghĩa được sử dụng với một hệ thống phân tích chương trình cao cấp mà có các công cụ lexing/phân tích cú pháp như hệ thống con, gọi là The DMS Software Reengineering Toolkit. DMS sẽ tự động tạo AST từ các quy tắc ngữ pháp
trong đặc tả của trình phân tích cú pháp, làm cho các công cụ phân tích cú pháp trở thành công cụ phân tích cú pháp dễ dàng hơn nhiều. Cuối cùng, đặc tả của trình phân tích cú pháp chứa các khai báo "prettyprinter" được gọi là, cho phép DMS tái tạo lại văn bản nguồn từ các AST. (Mục đích thực sự của ngữ pháp là cho phép chúng ta xây dựng ASTs đại diện cho lắp ráp hướng dẫn, và sau đó nhổ chúng ra để được làm thức ăn cho một nhà lắp ráp thật!)

Một điều cần chú ý: cách lexemes và quy tắc ngữ pháp được trình bày theo (metasyntxax!) thay đổi đôi chút giữa các hệ thống máy phát lexer/parser khác nhau. Cú pháp của các đặc tả dựa trên DMS không là ngoại lệ. DMS có các quy tắc ngữ pháp tương đối phức tạp , thực sự không thực tế để giải thích trong không gian sẵn có tại đây. Bạn sẽ phải sống với ý tưởng rằng các hệ thống khác sử dụng các ký hiệu tương tự, cho EBNF cho các quy tắc và các biến thể biểu thức chính quy cho từ vựng.

Với lợi ích của OP, ông có thể thực hiện tương tự lexer/parsers với bất kỳ công cụ lexer/máy phát điện phân tích cú pháp, ví dụ như, FLEX/YACC, javacc, ANTLR, ...

******* *** LEXER **************

-- M6809.lex: Lexical Description for M6809 
-- Copyright (C) 1989,1999-2002 Ira D. Baxter 

%% 
#mainmode Label 

#macro digit "[0-9]" 
#macro hexadecimaldigit "<digit>|[a-fA-F]" 

#macro comment_body_character "[\u0009 \u0020-\u007E]" -- does not include NEWLINE 

#macro blank "[\u0000 \ \u0009]" 

#macro hblanks "<blank>+" 

#macro newline "\u000d \u000a? \u000c? | \u000a \u000c?" -- form feed allowed only after newline 

#macro bare_semicolon_comment "\; <comment_body_character>* " 

#macro bare_asterisk_comment "\* <comment_body_character>* " 

...[snip] 

#macro hexadecimal_digit "<digit> | [a-fA-F]" 

#macro binary_digit "[01]" 

#macro squoted_character "\' [\u0021-\u007E]" 

#macro string_character "[\u0009 \u0020-\u007E]" 

%%Label -- (First mode) processes left hand side of line: labels, opcodes, etc. 

#skip "(<blank>*<newline>)+" 
#skip "(<blank>*<newline>)*<blank>+" 
    << (GotoOpcodeField ?) >> 

#precomment "<comment_line><newline>" 

#preskip "(<blank>*<newline>)+" 
#preskip "(<blank>*<newline>)*<blank>+" 
    << (GotoOpcodeField ?) >> 

-- Note that an apparant register name is accepted as a label in this mode 
#token LABEL [STRING] "<identifier>" 
    << (local (;; (= [TokenScan natural] 1) ; process all string characters 
     (= [TokenLength natural] ?:TokenCharacterCount)= 
     (= [TokenString (reference TokenBodyT)] (. ?:TokenCharacters)) 
     (= [Result (reference string)] (. ?:Lexeme:Literal:String:Value)) 
     [ThisCharacterCode natural] 
     (define Ordinala #61) 
     (define Ordinalf #66) 
     (define OrdinalA #41) 
     (define OrdinalF #46) 
    );; 
    (;; (= (@ Result) `') ; start with empty string 
    (while (<= TokenScan TokenLength) 
     (;; (= ThisCharacterCode (coerce natural TokenString:TokenScan)) 
     (+= TokenScan) ; bump past character 
     (ifthen (>= ThisCharacterCode Ordinala) 
      (-= ThisCharacterCode #20) ; fold to upper case 
     )ifthen 
     (= (@ Result) (append (@ Result) (coerce character ThisCharacterCode)))= 

     );; 
    )while 
    );; 
)local 
    (= ?:Lexeme:Literal:String:Format (LiteralFormat:MakeCompactStringLiteralFormat 0)) ; nothing interesting in string 
    (GotoLabelList ?) 
    >> 

%%OpcodeField 

#skip "<hblanks>" 
    << (GotoEOLComment ?) >> 
#ifnotoken 
    << (GotoEOLComment ?) >> 

-- Opcode field tokens 
#token 'ABA'  "[aA][bB][aA]" 
    << (GotoEOLComment ?) >> 
#token 'ABX'  "[aA][bB][xX]" 
    << (GotoEOLComment ?) >> 
#token 'ADC'  "[aA][dD][cC]" 
    << (GotoABregister ?) >> 
#token 'ADCA'  "[aA][dD][cC][aA]" 
    << (GotoOperand ?) >> 
#token 'ADCB'  "[aA][dD][cC][bB]" 
    << (GotoOperand ?) >> 
#token 'ADCD'  "[aA][dD][cC][dD]" 
    << (GotoOperand ?) >> 
#token 'ADD'  "[aA][dD][dD]" 
    << (GotoABregister ?) >> 
#token 'ADDA'  "[aA][dD][dD][aA]" 
    << (GotoOperand ?) >> 
#token 'ADDB'  "[aA][dD][dD][bB]" 
    << (GotoOperand ?) >> 
#token 'ADDD'  "[aA][dD][dD][dD]" 
    << (GotoOperand ?) >> 
#token 'AND'  "[aA][nN][dD]" 
    << (GotoABregister ?) >> 
#token 'ANDA'  "[aA][nN][dD][aA]" 
    << (GotoOperand ?) >> 
#token 'ANDB'  "[aA][nN][dD][bB]" 
    << (GotoOperand ?) >> 
#token 'ANDCC'  "[aA][nN][dD][cC][cC]" 
    << (GotoRegister ?) >> 
...[long list of opcodes snipped] 

#token IDENTIFIER [STRING] "<identifier>" 
    << (local (;; (= [TokenScan natural] 1) ; process all string characters 
     (= [TokenLength natural] ?:TokenCharacterCount)= 
     (= [TokenString (reference TokenBodyT)] (. ?:TokenCharacters)) 
     (= [Result (reference string)] (. ?:Lexeme:Literal:String:Value)) 
     [ThisCharacterCode natural] 
     (define Ordinala #61) 
     (define Ordinalf #66) 
     (define OrdinalA #41) 
     (define OrdinalF #46) 
    );; 
    (;; (= (@ Result) `') ; start with empty string 
    (while (<= TokenScan TokenLength) 
     (;; (= ThisCharacterCode (coerce natural TokenString:TokenScan)) 
     (+= TokenScan) ; bump past character 
     (ifthen (>= ThisCharacterCode Ordinala) 
      (-= ThisCharacterCode #20) ; fold to upper case 
     )ifthen 
     (= (@ Result) (append (@ Result) (coerce character ThisCharacterCode)))= 

     );; 
    )while 
    );; 
)local 
    (= ?:Lexeme:Literal:String:Format (LiteralFormat:MakeCompactStringLiteralFormat 0)) ; nothing interesting in string 
    (GotoOperandField ?) 
    >> 

#token '#' "\#" -- special constant introduction (FDB) 
    << (GotoDataField ?) >> 

#token NUMBER [NATURAL] "<decimal_number>" 
    << (local [format LiteralFormat:NaturalLiteralFormat] 
    (;; (= ?:Lexeme:Literal:Natural:Value (ConvertDecimalTokenStringToNatural (. format) ? 0 0)) 
    (= ?:Lexeme:Literal:Natural:Format (LiteralFormat:MakeCompactNaturalLiteralFormat format)) 
    );; 
)local 
(GotoOperandField ?) 
    >> 

#token NUMBER [NATURAL] "\$ <hexadecimal_digit>+" 
    << (local [format LiteralFormat:NaturalLiteralFormat] 
    (;; (= ?:Lexeme:Literal:Natural:Value (ConvertHexadecimalTokenStringToNatural (. format) ? 1 0)) 
    (= ?:Lexeme:Literal:Natural:Format (LiteralFormat:MakeCompactNaturalLiteralFormat format)) 
    );; 
)local 
(GotoOperandField ?) 
    >> 

#token NUMBER [NATURAL] "\% <binary_digit>+" 
    << (local [format LiteralFormat:NaturalLiteralFormat] 
    (;; (= ?:Lexeme:Literal:Natural:Value (ConvertBinaryTokenStringToNatural (. format) ? 1 0)) 
    (= ?:Lexeme:Literal:Natural:Format (LiteralFormat:MakeCompactNaturalLiteralFormat format)) 
    );; 
)local 
(GotoOperandField ?) 
    >> 

#token CHARACTER [CHARACTER] "<squoted_character>" 
    << (= ?:Lexeme:Literal:Character:Value (TokenStringCharacter ? 2)) 
    (= ?:Lexeme:Literal:Character:Format (LiteralFormat:MakeCompactCharacterLiteralFormat 0 0)) ; nothing special about character 
    (GotoOperandField ?) 
    >> 


%%OperandField 

#skip "<hblanks>" 
    << (GotoEOLComment ?) >> 
#ifnotoken 
    << (GotoEOLComment ?) >> 

-- Tokens signalling switch to index register modes 
#token ',' "\," 
    <<(GotoRegisterField ?)>> 
#token '[' "\[" 
    <<(GotoRegisterField ?)>> 

-- Operators for arithmetic syntax 
#token '!!' "\!\!" 
#token '!' "\!" 
#token '##' "\#\#" 
#token '#' "\#" 
#token '&' "\&" 
#token '(' "\(" 
#token ')' "\)" 
#token '*' "\*" 
#token '+' "\+" 
#token '-' "\-" 
#token '/' "\/" 
#token '//' "\/\/" 
#token '<' "\<" 
#token '<' "\<" 
#token '<<' "\<\<" 
#token '<=' "\<\=" 
#token '</' "\<\/" 
#token '=' "\=" 
#token '>' "\>" 
#token '>' "\>" 
#token '>=' "\>\=" 
#token '>>' "\>\>" 
#token '>/' "\>\/" 
#token '\\' "\\" 
#token '|' "\|" 
#token '||' "\|\|" 

#token NUMBER [NATURAL] "<decimal_number>" 
    << (local [format LiteralFormat:NaturalLiteralFormat] 
    (;; (= ?:Lexeme:Literal:Natural:Value (ConvertDecimalTokenStringToNatural (. format) ? 0 0)) 
    (= ?:Lexeme:Literal:Natural:Format (LiteralFormat:MakeCompactNaturalLiteralFormat format)) 
    );; 
)local 
    >> 

#token NUMBER [NATURAL] "\$ <hexadecimal_digit>+" 
    << (local [format LiteralFormat:NaturalLiteralFormat] 
    (;; (= ?:Lexeme:Literal:Natural:Value (ConvertHexadecimalTokenStringToNatural (. format) ? 1 0)) 
    (= ?:Lexeme:Literal:Natural:Format (LiteralFormat:MakeCompactNaturalLiteralFormat format)) 
    );; 
)local 
    >> 

#token NUMBER [NATURAL] "\% <binary_digit>+" 
    << (local [format LiteralFormat:NaturalLiteralFormat] 
    (;; (= ?:Lexeme:Literal:Natural:Value (ConvertBinaryTokenStringToNatural (. format) ? 1 0)) 
    (= ?:Lexeme:Literal:Natural:Format (LiteralFormat:MakeCompactNaturalLiteralFormat format)) 
    );; 
)local 
    >> 

-- Notice that an apparent register is accepted as a label in this mode 
#token IDENTIFIER [STRING] "<identifier>" 
    << (local (;; (= [TokenScan natural] 1) ; process all string characters 
     (= [TokenLength natural] ?:TokenCharacterCount)= 
     (= [TokenString (reference TokenBodyT)] (. ?:TokenCharacters)) 
     (= [Result (reference string)] (. ?:Lexeme:Literal:String:Value)) 
     [ThisCharacterCode natural] 
     (define Ordinala #61) 
     (define Ordinalf #66) 
     (define OrdinalA #41) 
     (define OrdinalF #46) 
    );; 
    (;; (= (@ Result) `') ; start with empty string 
    (while (<= TokenScan TokenLength) 
     (;; (= ThisCharacterCode (coerce natural TokenString:TokenScan)) 
     (+= TokenScan) ; bump past character 
     (ifthen (>= ThisCharacterCode Ordinala) 
      (-= ThisCharacterCode #20) ; fold to upper case 
     )ifthen 
     (= (@ Result) (append (@ Result) (coerce character ThisCharacterCode)))= 

     );; 
    )while 
    );; 
)local 
    (= ?:Lexeme:Literal:String:Format (LiteralFormat:MakeCompactStringLiteralFormat 0)) ; nothing interesting in string 
    >> 

%%Register -- operand field for TFR, ANDCC, ORCC, EXG opcodes 

#skip "<hblanks>" 
#ifnotoken << (GotoRegisterField ?) >> 

%%RegisterField -- handles registers and indexing mode syntax 
-- In this mode, names that look like registers are recognized as registers 

#skip "<hblanks>" 
    << (GotoEOLComment ?) >> 
#ifnotoken 
    << (GotoEOLComment ?) >> 

#token '[' "\[" 
#token ']' "\]" 
#token '--' "\-\-" 
#token '++' "\+\+" 

#token 'A'  "[aA]" 
#token 'B'  "[bB]" 
#token 'CC'  "[cC][cC]" 
#token 'DP'  "[dD][pP] | [dD][pP][rR]" -- DPR shouldnt be needed, but found one instance 
#token 'D'  "[dD]" 
#token 'Z'  "[zZ]" 

-- Index register designations 
#token 'X'  "[xX]" 
#token 'Y'  "[yY]" 
#token 'U'  "[uU]" 
#token 'S'  "[sS]" 
#token 'PCR' "[pP][cC][rR]" 
#token 'PC'  "[pP][cC]" 

#token ',' "\," 

-- Operators for arithmetic syntax 
#token '!!' "\!\!" 
#token '!' "\!" 
#token '##' "\#\#" 
#token '#' "\#" 
#token '&' "\&" 
#token '(' "\(" 
#token ')' "\)" 
#token '*' "\*" 
#token '+' "\+" 
#token '-' "\-" 
#token '/' "\/" 
#token '<' "\<" 
#token '<' "\<" 
#token '<<' "\<\<" 
#token '<=' "\<\=" 
#token '<|' "\<\|" 
#token '=' "\=" 
#token '>' "\>" 
#token '>' "\>" 
#token '>=' "\>\=" 
#token '>>' "\>\>" 
#token '>|' "\>\|" 
#token '\\' "\\" 
#token '|' "\|" 
#token '||' "\|\|" 

#token NUMBER [NATURAL] "<decimal_number>" 
    << (local [format LiteralFormat:NaturalLiteralFormat] 
    (;; (= ?:Lexeme:Literal:Natural:Value (ConvertDecimalTokenStringToNatural (. format) ? 0 0)) 
    (= ?:Lexeme:Literal:Natural:Format (LiteralFormat:MakeCompactNaturalLiteralFormat format)) 
    );; 
)local 
    >> 

... [snip] 

%% -- end M6809.lex 

**************** PARSER ******** ******

-- M6809.ATG: Motorola 6809 assembly code parser 
-- (C) Copyright 1989;1999-2002 Ira D. Baxter; All Rights Reserved 

m6809 = sourcelines ; 

sourcelines = ; 
sourcelines = sourcelines sourceline EOL ; 
    <<PrettyPrinter>>: { V(CV(sourcelines[1]),H(sourceline,A<eol>(EOL))); } 

-- leading opcode field symbol should be treated as keyword. 

sourceline = ; 
sourceline = labels ; 
sourceline = optional_labels 'EQU' expression ; 
    <<PrettyPrinter>>: { H(optional_labels,A<opcode>('EQU'),A<operand>(expression)); } 
sourceline = LABEL 'SET' expression ; 
    <<PrettyPrinter>>: { H(A<firstlabel>(LABEL),A<opcode>('SET'),A<operand>(expression)); } 
sourceline = optional_label instruction ; 
    <<PrettyPrinter>>: { H(optional_label,instruction); } 
sourceline = optional_label optlabelleddirective ; 
    <<PrettyPrinter>>: { H(optional_label,optlabelleddirective); } 
sourceline = optional_label implicitdatadirective ; 
    <<PrettyPrinter>>: { H(optional_label,implicitdatadirective); } 
sourceline = unlabelleddirective ; 
sourceline = '?ERROR' ; 
    <<PrettyPrinter>>: { A<opcode>('?ERROR'); } 

optional_label = labels ; 
optional_label = LABEL ':' ; 
    <<PrettyPrinter>>: { H(A<firstlabel>(LABEL),':'); } 
optional_label = ; 

optional_labels = ; 
optional_labels = labels ; 
labels = LABEL ; 
    <<PrettyPrinter>>: { A<firstlabel>(LABEL); } 
labels = labels ',' LABEL ; 
    <<PrettyPrinter>>: { H(labels[1],',',A<otherlabels>(LABEL)); } 

unlabelleddirective = 'END' ; 
    <<PrettyPrinter>>: { A<opcode>('END'); } 
unlabelleddirective = 'END' expression ; 
    <<PrettyPrinter>>: { H(A<opcode>('END'),A<operand>(expression)); } 
unlabelleddirective = 'IF' expression EOL conditional ; 
    <<PrettyPrinter>>: { V(H(A<opcode>('IF'),H(A<operand>(expression),A<eol>(EOL))),CV(conditional)); } 
unlabelleddirective = 'IFDEF' IDENTIFIER EOL conditional ; 
    <<PrettyPrinter>>: { V(H(A<opcode>('IFDEF'),H(A<operand>(IDENTIFIER),A<eol>(EOL))),CV(conditional)); } 
unlabelleddirective = 'IFUND' IDENTIFIER EOL conditional ; 
    <<PrettyPrinter>>: { V(H(A<opcode>('IFUND'),H(A<operand>(IDENTIFIER),A<eol>(EOL))),CV(conditional)); } 
unlabelleddirective = 'INCLUDE' FILENAME ; 
    <<PrettyPrinter>>: { H(A<opcode>('INCLUDE'),A<operand>(FILENAME)); } 
unlabelleddirective = 'LIST' expression ; 
    <<PrettyPrinter>>: { H(A<opcode>('LIST'),A<operand>(expression)); } 
unlabelleddirective = 'NAME' IDENTIFIER ; 
    <<PrettyPrinter>>: { H(A<opcode>('NAME'),A<operand>(IDENTIFIER)); } 
unlabelleddirective = 'ORG' expression ; 
    <<PrettyPrinter>>: { H(A<opcode>('ORG'),A<operand>(expression)); } 
unlabelleddirective = 'PAGE' ; 
    <<PrettyPrinter>>: { A<opcode>('PAGE'); } 
unlabelleddirective = 'PAGE' HEADING ; 
    <<PrettyPrinter>>: { H(A<opcode>('PAGE'),A<operand>(HEADING)); } 
unlabelleddirective = 'PCA' expression ; 
    <<PrettyPrinter>>: { H(A<opcode>('PCA'),A<operand>(expression)); } 
unlabelleddirective = 'PCC' expression ; 
    <<PrettyPrinter>>: { H(A<opcode>('PCC'),A<operand>(expression)); } 
unlabelleddirective = 'PSR' expression ; 
    <<PrettyPrinter>>: { H(A<opcode>('PSR'),A<operand>(expression)); } 
unlabelleddirective = 'TABS' numberlist ; 
    <<PrettyPrinter>>: { H(A<opcode>('TABS'),A<operand>(numberlist)); } 
unlabelleddirective = 'TITLE' HEADING ; 
    <<PrettyPrinter>>: { H(A<opcode>('TITLE'),A<operand>(HEADING)); } 
unlabelleddirective = 'WITH' settings ; 
    <<PrettyPrinter>>: { H(A<opcode>('WITH'),A<operand>(settings)); } 

settings = setting ; 
settings = settings ',' setting ; 
    <<PrettyPrinter>>: { H*; } 
setting = 'WI' '=' NUMBER ; 
    <<PrettyPrinter>>: { H*; } 
setting = 'DE' '=' NUMBER ; 
    <<PrettyPrinter>>: { H*; } 
setting = 'M6800' ; 
setting = 'M6801' ; 
setting = 'M6809' ; 
setting = 'M6811' ; 

-- collects lines of conditional code into blocks 
conditional = 'ELSEIF' expression EOL conditional ; 
    <<PrettyPrinter>>: { V(H(A<opcode>('ELSEIF'),H(A<operand>(expression),A<eol>(EOL))),CV(conditional[1])); } 
conditional = 'ELSE' EOL else ; 
    <<PrettyPrinter>>: { V(H(A<opcode>('ELSE'),A<eol>(EOL)),CV(else)); } 
conditional = 'FIN' ; 
    <<PrettyPrinter>>: { A<opcode>('FIN'); } 
conditional = sourceline EOL conditional ; 
    <<PrettyPrinter>>: { V(H(sourceline,A<eol>(EOL)),CV(conditional[1])); } 

else = 'FIN' ; 
    <<PrettyPrinter>>: { A<opcode>('FIN'); } 
else = sourceline EOL else ; 
    <<PrettyPrinter>>: { V(H(sourceline,A<eol>(EOL)),CV(else[1])); } 

-- keyword-less directive, generates data tables 

implicitdatadirective = implicitdatadirective ',' implicitdataitem ; 
    <<PrettyPrinter>>: { H*; } 
implicitdatadirective = implicitdataitem ; 

implicitdataitem = '#' expression ; 
    <<PrettyPrinter>>: { A<operand>(H('#',expression)); } 
implicitdataitem = '+' expression ; 
    <<PrettyPrinter>>: { A<operand>(H('+',expression)); } 
implicitdataitem = '-' expression ; 
    <<PrettyPrinter>>: { A<operand>(H('-',expression)); } 
implicitdataitem = expression ; 
    <<PrettyPrinter>>: { A<operand>(expression); } 
implicitdataitem = STRING ; 
    <<PrettyPrinter>>: { A<operand>(STRING); } 

-- instructions valid for m680C (see Software Dynamics ASM manual) 
instruction = 'ABA' ; 
    <<PrettyPrinter>>: { A<opcode>('ABA'); } 
instruction = 'ABX' ; 
    <<PrettyPrinter>>: { A<opcode>('ABX'); } 

instruction = 'ADC' 'A' operandfetch ; 
    <<PrettyPrinter>>: { H(A<opcode>(H('ADC','A')),A<operand>(operandfetch)); } 
instruction = 'ADC' 'B' operandfetch ; 
    <<PrettyPrinter>>: { H(A<opcode>(H('ADC','B')),A<operand>(operandfetch)); } 
instruction = 'ADCA' operandfetch ; 
    <<PrettyPrinter>>: { H(A<opcode>('ADCA'),A<operand>(operandfetch)); } 
instruction = 'ADCB' operandfetch ; 
    <<PrettyPrinter>>: { H(A<opcode>('ADCB'),A<operand>(operandfetch)); } 
instruction = 'ADCD' operandfetch ; 
    <<PrettyPrinter>>: { H(A<opcode>('ADCD'),A<operand>(operandfetch)); } 

instruction = 'ADD' 'A' operandfetch ; 
    <<PrettyPrinter>>: { H(A<opcode>(H('ADD','A')),A<operand>(operandfetch)); } 
instruction = 'ADD' 'B' operandfetch ; 
    <<PrettyPrinter>>: { H(A<opcode>(H('ADD','B')),A<operand>(operandfetch)); } 
instruction = 'ADDA' operandfetch ; 
    <<PrettyPrinter>>: { H(A<opcode>('ADDA'),A<operand>(operandfetch)); } 

[..snip...] 

-- condition code mask for ANDCC and ORCC 
conditionmask = '#' expression ; 
    <<PrettyPrinter>>: { H*; } 
conditionmask = expression ; 

target = expression ; 

operandfetch = '#' expression ; --immediate 
    <<PrettyPrinter>>: { H*; } 

operandfetch = memoryreference ; 

operandstore = memoryreference ; 

memoryreference = '[' indexedreference ']' ; 
    <<PrettyPrinter>>: { H*; } 
memoryreference = indexedreference ; 

indexedreference = offset ; 
indexedreference = offset ',' indexregister ; 
    <<PrettyPrinter>>: { H*; } 
indexedreference = ',' indexregister ; 
    <<PrettyPrinter>>: { H*; } 
indexedreference = ',' '--' indexregister ; 
    <<PrettyPrinter>>: { H*; } 
indexedreference = ',' '-' indexregister ; 
    <<PrettyPrinter>>: { H*; } 
indexedreference = ',' indexregister '++' ; 
    <<PrettyPrinter>>: { H*; } 
indexedreference = ',' indexregister '+' ; 
    <<PrettyPrinter>>: { H*; } 

offset = '>' expression ; -- page zero ref 
    <<PrettyPrinter>>: { H*; } 
offset = '<' expression ; -- long reference 
    <<PrettyPrinter>>: { H*; } 
offset = expression ; 
offset = 'A' ; 
offset = 'B' ; 
offset = 'D' ; 

registerlist = registername ; 
registerlist = registerlist ',' registername ; 
    <<PrettyPrinter>>: { H*; } 

registername = 'A' ; 
registername = 'B' ; 
registername = 'CC' ; 
registername = 'DP' ; 
registername = 'D' ; 
registername = 'Z' ; 
registername = indexregister ; 

indexregister = 'X' ; 
indexregister = 'Y' ; 
indexregister = 'U' ; -- not legal on M6811 
indexregister = 'S' ; 
indexregister = 'PCR' ; 
indexregister = 'PC' ; 

expression = sum '=' sum ; 
    <<PrettyPrinter>>: { H*; } 
expression = sum '<<' sum ; 
    <<PrettyPrinter>>: { H*; } 
expression = sum '</' sum ; 
    <<PrettyPrinter>>: { H*; } 
expression = sum '<=' sum ; 
    <<PrettyPrinter>>: { H*; } 
expression = sum '<' sum ; 
    <<PrettyPrinter>>: { H*; } 
expression = sum '>>' sum ; 
    <<PrettyPrinter>>: { H*; } 
expression = sum '>/' sum ; 
    <<PrettyPrinter>>: { H*; } 
expression = sum '>=' sum ; 
    <<PrettyPrinter>>: { H*; } 
expression = sum '>' sum ; 
    <<PrettyPrinter>>: { H*; } 
expression = sum '#' sum ; 
    <<PrettyPrinter>>: { H*; } 
expression = sum ; 

sum = product ; 
sum = sum '+' product ; 
    <<PrettyPrinter>>: { H*; } 
sum = sum '-' product ; 
    <<PrettyPrinter>>: { H*; } 
sum = sum '!' product ; 
    <<PrettyPrinter>>: { H*; } 
sum = sum '!!' product ; 
    <<PrettyPrinter>>: { H*; } 

product = term '*' product ; 
    <<PrettyPrinter>>: { H*; } 
product = term '||' product ; -- wrong? 
    <<PrettyPrinter>>: { H*; } 
product = term '/' product ; 
    <<PrettyPrinter>>: { H*; } 
product = term '//' product ; 
    <<PrettyPrinter>>: { H*; } 
product = term '&' product ; 
    <<PrettyPrinter>>: { H*; } 
product = term '##' product ; 
    <<PrettyPrinter>>: { H*; } 
product = term ; 

term = '+' term ; 
    <<PrettyPrinter>>: { H*; } 
term = '-' term ; 
    <<PrettyPrinter>>: { H*; } 
term = '\\' term ; -- complement 
    <<PrettyPrinter>>: { H*; } 
term = '&' term ; -- not 

term = IDENTIFIER ; 
term = NUMBER ; 
term = CHARACTER ; 
term = '*' ; 
term = '(' expression ')' ; 
    <<PrettyPrinter>>: { H*; } 

numberlist = NUMBER ; 
numberlist = numberlist ',' NUMBER ; 
    <<PrettyPrinter>>: { H*; } 
+0

Ira, cảm ơn bạn đã phản hồi tốt (tôi đã cố gắng xếp hạng điều này nhưng tôi không đủ kinh nghiệm). Tôi tự hỏi nếu bạn có một ví dụ lexer và/hoặc phân tích cú pháp trong đó sử dụng phương pháp này để tôi có thể có một cái nhìn hoặc nếu không, bất kỳ cơ hội của một số mã giả để có được tôi di chuyển về phía trước với điều này :).Trân trọng –

+1

@Gary: Hãy coi chừng những gì bạn yêu cầu:} Xem các chỉnh sửa đối với câu trả lời nhỏ của tôi biến nó thành một câu trả lời khổng lồ. –

+0

@Gary: PS, để "xếp thứ hạng này", chỉ cần nhấp vào hình tam giác hướng lên trên phía trên điểm số bên cạnh phần bắt đầu của câu trả lời. : -} –

3

BNF thường được sử dụng cho các ngôn ngữ có cấu trúc, lồng nhau như Pascal, C++ hoặc bất kỳ thứ gì có nguồn gốc từ họ Algol (bao gồm các ngôn ngữ hiện đại như C#). Nếu tôi đã thực hiện một bộ lắp ráp, tôi có thể sử dụng một số biểu thức thông thường đơn giản để phù hợp với mẫu mã và toán hạng. Nó được một lúc kể từ khi tôi đã sử dụng ngôn ngữ lắp ráp Z80, nhưng bạn có thể sử dụng một cái gì đó như:

/\s*(\w{2,3})\s+((\w+)(,\w+)?)?/ 

này sẽ phù hợp với bất kỳ dòng trong đó bao gồm một opcode hai hoặc ba chữ cái theo sau một hoặc hai toán hạng tách bằng dấu phẩy. Sau khi giải nén một dây chuyền lắp ráp như thế này, bạn sẽ xem xét mã opcode và tạo ra các byte đúng cho lệnh, bao gồm các giá trị của toán hạng nếu có. Các loại phân tích cú pháp mà tôi đã phác thảo ở trên bằng cách sử dụng cụm từ thông dụng sẽ được gọi là trình phân tích cú pháp "ad hoc", về cơ bản có nghĩa là bạn phân tách và kiểm tra đầu vào trên một số loại cơ sở chặn (trong trường hợp ngôn ngữ lắp ráp). dòng văn bản).

2

Tôi không nghĩ bạn cần phải suy nghĩ quá mức. Không có điểm nào làm cho trình phân tích tách "LD A, A" thành hoạt động tải, đích và thanh ghi nguồn, khi bạn chỉ có thể chuỗi khớp với toàn bộ điều (trường hợp modulo và khoảng trống) vào một mã trực tiếp.

Không có nhiều mã opcodes, và chúng không được sắp xếp sao cho bạn thực sự nhận được nhiều lợi ích từ việc phân tích cú pháp và hiểu IMO lắp ráp. Rõ ràng bạn cần một trình phân tích cú pháp cho các đối số byte/address/indexing, nhưng khác với tôi, tôi chỉ có một tra cứu một đối một.

+1

Cảm ơn phản hồi của bạn ... Tôi đồng ý rằng đi xuống một con đường đơn giản hơn nhưng tôi cũng quan tâm đến việc mở rộng ngôn ngữ này sang ngôn ngữ phức tạp hơn và tôi muốn sử dụng các tính năng ngay từ đầu ... là sự khác biệt trong một số phần khác của ASM như equ, .db, .ds, .dw, #include,() và sau đó chúng ta bắt đầu nhận được vào các câu lệnh case đơn giản IF ELSE. Hơn nữa, đây cũng là một bài tập trong việc học các khái niệm về BNF và sử dụng nó để thực hiện đơn giản hơn này. –