문제

BNF를 배우려고 노력하고 일부 Z80 ASM 코드를 조립하려고합니다. 나는 두 분야 모두를 처음 접했기 때문에 내 질문은 내가 올바른 길을 가고 있는가? Z80 ASM의 형식을 EBNF로 작성하려고 노력하여 소스에서 기계 코드를 만들기 위해 거기에서 어디로 가야할지 파악할 수 있습니다. 지금은 다음과 같습니다.

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

내가 잘못되면 방향성 피드백이 우수합니다.

도움이 되었습니까?

해결책

구식 어셈블러는 일반적으로 어셈블러로 손으로 코딩되었으며 ADHOC 구문 분석 기술을 사용하여 조립 소스 라인을 처리하여 실제 어셈블러 코드를 생성했습니다. 어셈블러 구문이 간단 할 때 (예 : 항상 opcode reg, operand) 이것은 충분히 잘 작동했습니다.

현대 기계는 많은 지침 변형과 피연산자가있는 지저분하고 불쾌한 지시 세트를 가지고 있으며, 이는 복잡한 구문으로 표현되어 여러 인덱스 레지스터가 피연산자 표현식에 참여할 수 있도록 할 수 있습니다. 다양한 유형의 추가 연산자가 고정되고 재배치 가능한 상수로 정교한 조립 시간 표현식을 허용하면이를 복잡하게 만듭니다. 조건부 편집, 매크로, 구조화 된 데이터 선언 등을 허용하는 정교한 어셈블러는 모두 구문에 새로운 요구를 추가합니다. 임시 방법 으로이 모든 구문을 처리하는 것은 매우 어렵고 파서 생성기가 발명 된 이유입니다.

BNF와 파서 생성기를 사용하는 것은 Z80과 같은 레거시 프로세서의 경우에도 현대 어셈블러를 구축하는 매우 합리적인 방법입니다. 나는 6800/6809와 같은 Motorola 8 비트 머신 용 어셈블러를 구축했으며 현대 x86을 위해 동일한 작업을 준비하고 있습니다. 나는 당신이 정확한 길로 향하고 있다고 생각합니다.

********** 편집 **************** OP는 예를 들어 Lexer 및 Parser 정의를 요청했습니다. 나는 여기서 두 가지를 모두 제공했다.

이것들은 6809 Asssembler에 대한 실제 사양에서 발췌 한 것입니다. 완전한 정의는 여기에서 샘플 크기의 2-3 배입니다.

공간을 유지하기 위해, 나는 이러한 정의의 요점 인 다크 코너 복잡성을 많이 편집했습니다. 하나는 명백한 복잡성에 의해 실망 될 수있다. 요점은 그러한 정의로 당신은 설명하다 언어의 모양은 절차 적으로 코드가 아닙니다. 이 모든 것을 임시 방식으로 코딩하면 훨씬 더 높은 복잡성을 지불하고 유지 가능성이 훨씬 낮습니다.

또한 이러한 정의는 하위 시스템으로 부르기/구문 분석 도구가있는 고급 프로그램 분석 시스템과 함께 사용되었다는 것을 아는 데 도움이 될 것입니다.DMS 소프트웨어 리엔지니어링 툴킷. DMS는 자동으로 AST를 구축합니다
구문 분석의 문법 규칙은 구문 분석 도구를 훨씬 쉽게 구조화 할 수 있습니다. 마지막으로, 파서 사양에는 소위 "PrettyPrinter"선언이 포함되어있어 DMS가 ASTS에서 소스 텍스트를 재생할 수 있습니다. (그레이머의 실제 목적은 우리가 어셈블러 지침을 나타내는 asts를 만들 수있게 한 다음, 실제 어셈블러에게 공급되도록 뱉어 냈습니다!)

한 가지 주목 : Lexemes 및 Grammar 규칙이 어떻게 언급되는지 (Metasyntxax!)는 Lexer/Parser Generator Systems에 따라 다소 다양합니다. DMS 기반 사양의 구문도 예외는 아닙니다. DMS는 상대적으로 정교한 문법 규칙을 가지고 있으며, 여기에서 사용 가능한 공간에서 설명하기에는 실용적이지 않습니다. 다른 시스템은 규칙에 대한 EBNF 및 Lexemes의 정규 표현 변형에 대해 유사한 표기법을 사용한다는 아이디어를 가지고 살아야합니다.

OP의 관심사를 감안할 때, 그는 Lexer/Parser Generator 도구 (예 : Flex/YACC, Javacc, Antlr, ...)와 유사한 Lexer/Parsers를 구현할 수 있습니다.

********** 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*; }

다른 팁

BNF는 일반적으로 Pascal, C ++ 또는 Algol 제품군 (C#과 같은 현대 언어 포함)과 같은 구조화 된 중첩 언어에 일반적으로 사용됩니다. 어셈블러를 구현하는 경우 간단한 정규 표현식을 사용하여 Opcode와 오페라를 패턴 할 수 있습니다. Z80 어셈블리 언어를 사용한 지 오래되었지만 다음과 같은 것을 사용할 수 있습니다.

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

이것은 2 또는 3 글자 오크 코드와 쉼표로 분리 된 하나 또는 2 개의 피연산자로 구성된 모든 라인과 일치합니다. 이와 같은 어셈블러 라인을 추출한 후에는 Opcode를보고 해당되는 경우 피연산자 값을 포함하여 명령에 대한 올바른 바이트를 생성합니다.

정규 표현식을 사용하여 위에서 설명한 파서의 유형을 "임시"파서라고합니다. 이는 본질적으로 어떤 종류의 블록 기준으로 입력을 분할하고 검사하는 것을 의미합니다 (텍스트 라인 별 어셈블리 언어의 경우).

나는 당신이 그것을 지나치게 생각할 필요가 없다고 생각합니다. 로드 작업, 대상 및 소스 레지스터로 "ld a, a"를 분리하는 구문 분석기를 만들 수있는 것은 없습니다.

그다지 많은 opcodes는 없으며, 당신이 어셈블러 IMO를 파싱하고 이해함으로써 많은 혜택을 얻을 수있는 방식으로 배열되지 않았습니다. 분명히 당신은 바이트/주소/인덱싱 인수에 대한 구문 분석기가 필요하지만 그 외에는 일대일 조회를 가질 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top