2009-08-22 9 views
9

Próbuję nauczyć się BNF i próbować zmontować kod ASM Z80. Ponieważ jestem nowy w obu dziedzinach, moje pytanie brzmi: czy jestem na dobrej drodze? Próbuję napisać format Z80 ASM jako EBNF, dzięki czemu mogę dowiedzieć się, skąd się udać, aby utworzyć kod maszynowy ze źródła. W tej chwili mam następujące:Struktura Z80 ASM BNF ... czy jestem na dobrej drodze?

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" ; 

Jakikolwiek zwrot kierunkowy, jeśli się nie uda, byłby doskonały.

+0

Dupek z http://stackoverflow.com/questions/1305091/writing-an-z80-assembler-lexi ng-asm-and-building-a-parse-tree-using-composition przez tegoż użytkownika –

+3

@Butterworth: nie duplikat. Drugie pytanie dotyczy przekazywania informacji o drzewku, które mógłby utworzyć za pomocą gramatyki. To pytanie dotyczy tego, czy powinien używać gramatyki, a jeśli tak, to jak będzie wyglądać. Odpowiedź na to pytanie jest warunkiem wstępnym, aby inny był interesujący. –

Odpowiedz

16

Old-school asemblery były zwykle kodowane ręcznie w asembler i używane techniki parsowania adhoc do przetwarzania linii źródłowych zespołu do produkcji rzeczywistego kodu asemblera. Gdy składnia asemblera jest prosta (np. Zawsze OPCODE REG, OPERAND), to działało wystarczająco dobrze.

Współczesne maszyny mają niechlujne, nieprzyjemne zestawy instrukcji z dużą ilością wariantów instrukcji i operandów, które mogą być wyrażane za pomocą złożonej składni, umożliwiającej wielu rejestrom indeksowym udział w wyrażeniu operandu. Umożliwianie skomplikowanych wyrażeń czasowych w połączeniu z stałymi i relokowalnymi stałymi z różnymi typami operatorów dodających komplikuje to. Wyrafinowane asemblery pozwalające na kompilację warunkową, makra, deklaracje danych strukturalnych itp., Wszystko to dodaje nowe wymagania dotyczące składni. Przetwarzanie całej tej składni metodami ad hoc jest bardzo trudne i jest przyczyną wynalezienia generatorów analizatorów składni.

Korzystanie z BNF i generatora analizatora składni jest bardzo rozsądnym sposobem na zbudowanie nowoczesnego asemblera, nawet dla starszego procesora, takiego jak Z80. Zbudowałem takie assemblery dla 8-bitowych komputerów Motoroli, takich jak 6800/6809, i przygotowuję się do tego samego dla nowoczesnego x86. Myślę, że zmierzacie dokładnie tą właściwą ścieżką.

********** EDYCJA **************** OP poprosił np. O definicje leksera i parsera. Podaję oba tutaj.

Są to fragmenty prawdziwych specyfikacji dla 6869 assemblera. Kompletne definicje mają rozmiar 2-3x tutaj.

Aby zwolnić miejsce, zredagowałem znaczną część złożoności ciemnego kąta , która jest punktem tych definicji. Jeden może być przerażony przez złożoność apparant; Punktem wyjścia jest to, że przy takich definicjach próbujesz uzyskać kształt języka, a nie kodować go proceduralnie. Zapłacisz znacznie wyższą złożoność, jeśli zakoduje to wszystko w sposób ad hoc, a będzie to o wiele trudniejsze do utrzymania niż .

To będzie również pomocne, aby wiedzieć, że te definicje stosowane są z wysokiej klasy systemu analizy program posiada narzędzia Lexing/analizowania jako podsystemy, zwany The DMS Software Reengineering Toolkit. DMS automatycznie zbuduje AST z reguł gramatycznych
w analizie analizatora składni, co sprawia, że ​​łatwiej jest budować dużo narzędzi do analizowania składni. Wreszcie, specyfikacja parsera zawiera tak zwane deklaracje "prettyprinter" , które umożliwiają DMS odtworzenie tekstu źródłowego z AST. (Prawdziwym celem Grammer było umożliwienie nam budować ASTs reprezentujących asemblera instrukcjami, a następnie wypluć je do karmienia prawdziwego asemblerze!)

Jedno z dopiskiem: jak leksemy i reguły gramatyczne są wykazywane (metasyntxax!) różni się nieco pomiędzy różnymi generatorami generatorów/analizatorów składni. Składnia specyfikacji opartych na DMS nie jest wyjątkiem. DMS ma dość wyrafinowane reguły gramatyczne, które naprawdę nie są praktyczne do wyjaśnienia w dostępnej przestrzeni. Będziesz musiał żyć z pomysłem, że inne systemy używają podobnych oznaczeń, dla EBNF dla reguł i regularnych wariantów ekspresji dla leksemów.

Biorąc pod uwagę interesy PO za, może on realizować podobny Lexer/parserami z dowolnego narzędzia lexer/parser generator, np 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, dziękuję za dobre sprzężenie zwrotne (próbowałem rangować to, ale nie jestem wystarczająco doświadczony lol). Zastanawiałem się, czy miałeś przykład lexera i/lub parsera, który używa tego podejścia, abym mógł zobaczyć, czy nie, jakąkolwiek szansę na jakiś pseudo-kod, by skłonić mnie do posunięcia się naprzód z tym :).Pozdrawiam: –

+1

@Gary: Uważaj na to, o co prosisz:} Zobacz zmiany w mojej małej odpowiedzi, zmieniając ją w gigantyczną. –

+0

@Gary: PS, aby "uszeregować to", po prostu kliknij trójkąt skierowany w górę nad partyturą obok początku odpowiedzi. : -} –

3

BNF jest generalnie używany w językach strukturalnych, zagnieżdżonych, takich jak Pascal, C++, lub naprawdę cokolwiek pochodzących z rodziny Algol (która obejmuje nowoczesne języki, takie jak C#). Gdybym implementował asembler, mógłbym użyć kilku prostych wyrażeń regularnych, aby dopasować wzór do opcode i operandów. Minęło już trochę czasu od Użyłem asemblera Z80, ale można użyć coś takiego:

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

To pasuje do żadnej linii, która składa się z kodu operacji dwu- lub trzyliterowy po jednym lub dwóch argumentów rozdzielonych przecinkiem. Po wyodrębnieniu linii asemblera w ten sposób, spójrz na kod operacyjny i wygeneruj odpowiednie bajty dla instrukcji, w tym wartości operandów, jeśli to stosowne.

Typ analizatora składni, który opisałem powyżej za pomocą wyrażeń regularnych, byłby nazywany analizatorem składni "ad hoc", co w zasadzie oznacza, że ​​dzieli się i analizuje dane wejściowe na podstawie pewnego rodzaju bloku (w przypadku języka asemblerowego, przez linia tekstu).

2

Nie sądzę, że trzeba go przemyśleć. Nie ma sensu tworzenie parsera, który rozdziela "LD A, A" na operację ładowania, miejsce docelowe i rejestr źródłowy, kiedy można po prostu napisać dopasowanie całej rzeczy (przypadek modulo i biały) do jednego kodu operacyjnego bezpośrednio.

Nie ma zbyt wielu opcji i nie są one ułożone w taki sposób, aby naprawdę uzyskać wiele korzyści z analizowania i zrozumienia asemblera IMO. Oczywiście potrzebujesz parsera dla argumentów bajt/adres/indeksowania, ale poza tym po prostu szukam jeden do jednego.

+1

Dziękuję za twoją opinię ... Zgadzam się, że pójdę prostszą drogą, ale jestem zainteresowany rozszerzeniem tego na bardziej złożony język i postacią chciałbym korzystać z funkcji od samego początku ... są różnice w niektórych innych częściach ASM, takich jak equ, .db, .ds, .dw, #include,(), a następnie zaczynamy uzyskiwać proste instrukcje CAS IFSE. Co więcej, jest to również ćwiczenie w poznawaniu koncepcji BNF i wykorzystywaniu go do tego prostszego wdrożenia. –

Powiązane problemy