10
votes

Z80 ASM BNF Structure ... Suis-je sur la bonne voie?

J'essaie d'apprendre BNF et d'essayer d'assembler un code ASM Z80. Depuis que je suis nouveau dans les deux domaines, ma question est que je suis même sur la bonne voie? J'essaie d'écrire le format de Z80 ASM que EBNF afin que je puisse alors comprendre où aller de là pour créer un code de machine à partir de la source. Pour le moment, j'ai ce qui suit:

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


2 commentaires

Dupe de Stackoverflow.com/Questtions/1305091/... par le même idable


@ Butterworth: Pas de duplicata. L'autre question concerne la transmission d'informations autour de n'importe quel arbre qu'il pourrait construire à l'aide d'un grammer. Cette question concerne s'il devrait utiliser une grammaire, et si oui, à quoi cela ressemblerait. La réponse à cette question est une condition préalable à celle d'une autre étant intéressante.


3 Réponses :


3
votes

BNF est plus généralement utilisé pour des langages structurés et imbriqués comme Pascal, C ++ ou vraiment quelque chose dérivé de la famille d'algol (qui comprend des langues modernes comme c #). Si je mettais en place un assembleur, je pourrais utiliser certaines expressions régulières simples pour correspondre à l'opcode et aux opérandes. Cela fait longtemps que j'ai utilisé le langage de montage Z80, mais vous pouvez utiliser quelque chose comme: xxx

ceci correspondrait à n'importe quelle ligne consiste en un outil de deux ou trois lettres suivi d'une ou deux opérandes séparés par une virgule. Après avoir extrait une ligne d'assembleur comme celle-ci, vous examineriez l'opcode et généreriez les octets corrects pour l'instruction, y compris les valeurs des opérandes, le cas échéant.

Le type d'analyseur que j'ai décrit ci-dessus en utilisant régulièrement Les expressions seraient appelées un analyseur «ad hoc», qui signifie essentiellement que vous vous séparez et examinez l'entrée sur une seule base de bloc (dans le cas de la langue d'assemblage, par ligne de texte).


0 commentaires

2
votes

Je ne pense pas que vous ayez besoin de savoir. Il ne sert à rien de faire un analyseur qui élève "LD A, A" dans une opération de charge, une destination et un registre source, lorsque vous pouvez simplement faire correspondre le tout (étui modulo et espaces) dans un seul opcode directement.

Il n'y a pas beaucoup d'opcodes, et ils ne sont pas arrangés de manière à ce que vous obteniez vraiment beaucoup d'avantages de l'analyse et de la compréhension de l'assembleur imo. De toute évidence, vous auriez besoin d'un analyseur pour les arguments d'octets / d'adresse / d'indexation, mais autres que cela, je voudrais juste avoir une recherche unique.


1 commentaires

Merci pour vos commentaires ... je suis d'accord que je suis d'accord sur un chemin plus simpliste, mais aussi je suis intéressé à en prolonger cela dans une langue et une figurine plus complexes que je voudrais utiliser les caractéristiques du début ... Il y a aussi Différences dans d'autres parties de l'ASM, telles que SQU, .DB, .ds, .dw, #include, () et ensuite nous commençons à entrer dans de simples déclarations de cas si sinon. De plus, il s'agit également d'une exercice pour apprendre les concepts de BNF et l'utiliser pour cette mise en œuvre plus simpliste.



18
votes

Les assembleurs de l'ancienne école ont été typiquement codés à la main dans des techniques d'analyse adhoc utilisés pour traiter les lignes source d'assemblage pour produire un code d'assembleur réel. Lorsque l'assembleur Syntaxe est simple (par exemple, l'OPCODE ACCODEG, OPERAND) Cela a fonctionné assez bien.

Les machines modernes ont des instructions désordonnées et désordonnées avec de nombreuses variations d'instructions et opérandes, qui peuvent être exprimées avec une syntaxe complexe permettant de participer à plusieurs registres de l'index de participer. dans l'expression de l'opérande. Permettre aux expressions sophistiquées du temps d'assemblage avec des constantes fixes et relocatables avec différents types d'opérateurs d'addition compliquent cela. Des assembleurs sophistiqués permettant la compilation conditionnelle, les macros, les déclarations de données structurées, etc. Tout ajoutez de nouvelles demandes de syntaxe. Traitement de toute cette syntaxe par les méthodes ad hoc est très difficile et est la raison pour laquelle les générateurs d'analyseurs ont été inventés. P>

L'utilisation d'un BNF et un générateur d'analyseur est un moyen très raisonnable de construire un assembleur moderne, même pour un processeur de héritage. comme le z80. J'ai construit de tels assembleurs pour les machines de Motorola 8 bits tels que le 6800/6809 et je me prépare à faire de même pour un X86 moderne. Je pense que vous êtes dirigé exactement le bon chemin. P>

********** Modifier ***************** L'OP a demandé par exemple les définitions Lexer et Parser. J'ai fourni les deux ici. P>

Ce sont des extraits des spécifications réelles pour un âne 6809. Les définitions complètes sont de 2-3x la taille des échantillons ici. P>

Pour garder la place vers le bas, j'ai édité une grande partie de la complexité du coin sombre qui est le point de ces définitions. On pourrait être consterné par la complexité apparente; les point est que avec de telles définitions, vous essayez de décrivez em> le forme de la langue, pas de code informatique en procédural. Vous paierez une complexité significativement plus élevée si vous code tout cela de manière ad hoc, et ce sera loin moins maintenu. p>

Il sera également utile de savoir que ces définitions sont utilisés avec un système d'analyse de programme haut de gamme qui a des outils lexing / analyse comme sous-systèmes, appelé le Toolkit de réingorisation logiciel DMS . DMS construira automatiquement des asts de
règles de grammaire dans la spécification d'analyseur, ce qui en fait un beaucoup plus facile à utiliser des outils d'analyse. Dernièrement, La spécification d'analyse contient dite "prettyprinter" Les déclarations, qui permettent à DMS de régénérer le texte source des ASTS. (Le but réel de la marmmer était de nous permettre de construire des asts représentant l'assembleur instructions, puis les cracher pour être nourris à un réel assembleur!) p>

Une chose de note: comment les lexemes et les règles de grammaire sont indiquées (le métasyntxax!) Varie quelque peu entre différents systèmes de générateurs de lexer / parser. Les La syntaxe des spécifications basées sur le DMS ne fait pas exception. DMS a relativement sophistiqué Les règles de la grammaire à part entière, qui ne sont vraiment pas pratiques à expliquer dans l'espace disponible ici. Vous devrez vivre avec une idée que d'autres systèmes utilisent des notations similaires, pour EBNF pour des règles et des variantes d'expression régulières pour les Lexemes. P>

Compte tenu des intérêts de l'OP, il peut mettre en place des lexères / analyseurs similaires avec n'importe quel outil générateur lexer / parser, par exemple, Flex / Yacc, Javacc, Antlr, ... P>

********** Lexer ************** P>

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


8 commentaires

Ira, merci pour de bons commentaires (j'ai essayé de classer cela mais je ne suis pas assez expérimenté lol). Je me demandais si vous aviez un exemple de lexer et / ou d'un parseur qui utilise cette approche afin que je puisse être capable de jeter un coup d'œil ou, sinon, aucune chance de certains pseudo-code de me faire avancer avec ceci :). Meilleures salutations


@ Gary: méfiez-vous ce que vous demandez:} Voir les modifications à ma petite réponse en le transformant en un géant.


@ Gary: PS, pour "classer ça", cliquez simplement sur le triangle tourné vers le haut au-dessus du score à côté du début de la réponse. : -}


C'est frickin génial ... va aller le lire complètement! Merci malheureusement, je n'ai pas un classement personnel suffisamment élevé pour me permettre de classer cela en haut !! Quelqu'un pourrait-il s'il vous plaît le faire pour moi! :RÉ


Ok ... en commençant par le Lexer, je sais que votre code fait ce que je veux atteindre, je n'ai aucune idée de la façon de le représenter dans mon script Cible Langue ECMA. Regarder le tout début, je viens coincé presque instantanément avec comment représenter les macros, j'ai écrit des méthodes pour faire des vérifications telles que: // hexidecimal chiffre public hexidecimaldigit (str: string): booléen {retour décimaldigit (Str) || "A" || "B" || "C" || "D" || "E" || "F"; } ou chèques, mais une fois que je suis arrivé à plusieurs entrées de caractère, il va terriblement malol ... fonction publique opcode (str: string): booléen {// ???? } GP


Vous devez lire sur les générateurs de Lexer et d'analyseur et de la manière dont ils acceptent les définitions lexicales et les défenseurs des grammer et la manière dont ils génèrent du code pour mettre en œuvre ces définitions. Lisez n'importe quel livre sur "Flex" et "YACK" pour obtenir ce contexte. Puisque vous voulez travailler à Javacript, j'ai l'introduction parfaite pour vous: a "rel =" nfollow Noreferrer "> bayfronttechnologies.com/mc_tatutorial.html">a tutoriel sur les compilateurs de bâtiments (en JavaScript) . Ce didacticiel vous distrait pour un mois de soirées et vaut chaque instant. Il est basé sur un 1963 papier, et c'est comment j'ai appris à construire des compilateurs à l'origine.


D'une manière ou d'une autre, j'ai battu le lien dans la note précédente, et je ne sais pas comment modifier des commentaires, alors voici à nouveau le lien: Tutoriel "rel =" NOFOOLS NOREFERRER "> BAYFRONTTECHNOLOGIES.COM/MC_TUCTORIAL.HTML> Tutoriel sur les compilateurs de construction (Utilisation de JavaScript) . Il utilise une notation différente de celle que j'ai utilisée, mais les idées sont très similaires.


Pourquoi ne puis-je pas obtenir ce lien hypertexte dans une note? Semble Stackoverflow fait quelque chose au texte de liaison. OK, voici le lien comme texte brut: BayFrontTechnologies.com/mc_Tutorial.html Désolé pour les fumures .