////////////////////////////////////////////////////////////////////////////// // // File : avrparse.y // // Author : Tom Mortensen - Copyright (C) 1999 // // Description : This module implements the grammar file for AVRASM // // History // ======================================================================== // // 980902 : Tom - File created. // 990124 : Tom - Added GPL notice. // //////////////////////////////////////////////////////// Tom did this //////// // // Copyright notice: // // tavrasm - A GNU/Linux assembler for the Atmel AVR series // of microcontrollers. Copyright (C) 1999 Tom Mortensen // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // Tom Mortensen // // E-mail : tom@tavrasm.org // WWW : http://www.tavrasm.org // ////////////////////////////////////////////////////////////////////////////// %{ /// Include ////////////////////////////////////////////////////////////////// #include #include #include #include "avrasm.hh" #include "symbol.hh" #include "semantic.hh" #include "utils.hh" /// Extern /////////////////////////////////////////////////////////////////// GLOBALS(extern); extern char *yytext; /// Prototypes /////////////////////////////////////////////////////////////// int yylex(); /// yyerror ////////////////////////////////////////////////////////////////// void yyerror(char *s) { s = s; // Used for debugging purposes } /// Start of grammar ///////////////////////////////////////////////////////// %} /// Attribute union ////////////////////////////////////////////////////////// %union { regSA regid; instSA inst; opcodeSA opcode; valueSA val; nameSA name; symbolSA symb; indirectSA indi; functionSA func; stringSA string; } /// Terminal symbols that synthesizes default value ////////////////////////// %token STAR DIV MOD %token LS RS %token LE GE LESS GREAT EQ NE %token OR XOR AND %token OROR ANDAND %token LPAR RPAR %token COLON COMMA DOT EQUAL PLUS MINUS WAVE NOT %token EOL RESTART ENDOFFILE %token DEF EQU DB DW ORG ALIGN CSEG DSEG ESEG %token BYTE SET DEVICE STRING MACRODEF /// Attributes for terminal symbols ////////////////////////////////////////// %token REGISTER %token REGXYZ %token SYMBOL %token INTEGER %token COUNTER %token FUNCTION %token IREGREG %token IREGREGW %token IIMMIMM %token IREGIMM %token IREGIMMW %token IIMMREG %token IREG %token IIMM %token INOARGS %token IINDIRC %token ILPM %token STRING /// Attributes for non-terminal symbols ////////////////////////////////////// %type instruction %type lpminst %type expr %type indirectaddr %type registername %type unary_expr %type primary_expr %type mult_expr %type additive_expr %type shift_expr %type relational_expr %type equality_expr %type AND_expression %type exclusive_OR %type inclusive_OR %type logical_AND %type logical_OR %type composite_expr /// Expect 4 shift/reduce conflicts ////////////////////////////////////////// %expect 4 /// The goal symbol ////////////////////////////////////////////////////////// %start program %% // Start of grammar /////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // // program : programlist RESTART programlist // // e : // //////////////////////////////////////////////////////////////////////////// // // We start by defining the goal symbol 'program'. There is only one // production that can reduce the input to 'program': // // - 'programlist' RESTART 'programlist' // // with one 'programlist' for each pass. // // The symbol 'e' (or epsilon) is also defined. It should be considered // a terminal symbol, and is only used to increase readability. // //////////////////////////////////////////////////////////////////////////// program : programlist RESTART programlist ; e : ; //////////////////////////////////////////////////////////////////////////// // // programlist := programlist programelement | programelement // //////////////////////////////////////////////////////////////////////////// // // 'programlist' is a left recursive list production, that parses one or // more 'programelement's. // //////////////////////////////////////////////////////////////////////////// programlist : programlist programelement | programelement ; //////////////////////////////////////////////////////////////////////////// // // programelement := label instruction | label EOL | label directive | EOL // //////////////////////////////////////////////////////////////////////////// // // All instructions / defines are limited to a single line // //////////////////////////////////////////////////////////////////////////// programelement : label instruction { tolog(); } | label EOL { tolog(); } | label directive { tolog(); } | EOL { tolog(); } /// Error recovery ////////////////////////////////////////// | error EOL { error(E_UNKNOWN_OPCODE); tolog(); } ; //////////////////////////////////////////////////////////////////////////// // // instruction := IREGREG registername COMMA registername EOL // | IREGREGW registername COMMA registername EOL // | IREGREGW REGXYZ COMMA registername EOL // | IREGIMM registername COMMA expr EOL // | IREGIMMW registername COMMA expr EOL // | IREGIMMW REGXYZ COMMA expr EOL // | IIMMREG expr COMMA registername EOL // | IIMMIMM expr COMMA expr EOL // | IIMM expr EOL // | IREG registername EOL // | INOARGS EOL // | IINDIRC registername COMMA indirectaddr EOL // | IINDIRC indirectaddr COMMA registername EOL // //////////////////////////////////////////////////////////////////////////// // // There are nine different forms of 'instruction' : // // MOV r1, r1 ; Register / Register // MOV r1, 0x10 ; Register / expr // OUT 0x10, r1 ; expr / Register // BRBS 6, bitfound ; expr / expr // JMP 0x1000 ; expr // CLR r29 ; Register // CLI ; Noargs // LD r2, -Y ; Indirect // ST Y+, r2 ; Indirect // // Notice: LPM/ELPM are special, since they can be specified with or // without arguments (arrgh). // //////////////////////////////////////////////////////////////////////////// instruction : IREGREG registername COMMA registername EOL {genRegReg($1, $2, $4);} | IREGREGW registername COMMA registername EOL {genRegReg($1, $2, $4);} | IREGREGW REGXYZ COMMA registername EOL {genRegReg($1, $2, $4);} | IREGIMM registername COMMA expr EOL {genRegImm($1, $2, &$4);} | IREGIMMW registername COMMA expr EOL {genRegImm($1, $2, &$4);} | IREGIMMW REGXYZ COMMA expr EOL {genRegImm($1, $2, &$4);} | IIMMREG expr COMMA registername EOL {genImmReg($1, &$2, $4);} | IIMMIMM expr COMMA expr EOL {genImmImm($1, &$2, &$4);} | IIMM expr EOL {genImmedi($1, &$2);} | IREG registername EOL {genRegist($1, $2);} | INOARGS EOL {genNoargs($1);} | IINDIRC registername COMMA indirectaddr EOL {genIndirc($1, &$4, $2,TRUE);} | IINDIRC indirectaddr COMMA registername EOL {genIndirc($1, &$2, $4);} | lpminst /// Error recovery ////////////////////////////////////////// | IREGREG error EOL { error(E_REGISTER_EXPECTED); } | IREGREGW error EOL { error(E_REGISTER_EXPECTED); } | IREGIMM error EOL { error(E_INVALID_REGIMM_SPEC); } | IREGIMMW error EOL { error(E_INVALID_REGIMM_SPEC); } | IIMMREG error EOL { error(E_INVALID_REGIMM_SPEC); } | IIMMIMM error EOL { error(E_INVALID_IMMEDIATE_SPEC); } | IIMM error EOL { error(E_INVALID_IMMEDIATE_SPEC); } | IREG error EOL { error(E_INVALID_REGISTER_SPEC); } | INOARGS error EOL { error(E_NOARGS_EXPECTED_SPEC); } | IINDIRC error EOL { error(E_INVALID_REGISTER_SPEC); } ; //////////////////////////////////////////////////////////////////////////// // // lpminst := ILPM EOL | ILPM registername COMMA indirectaddr // //////////////////////////////////////////////////////////////////////////// // // Handles LPM and ELPM instructions // //////////////////////////////////////////////////////////////////////////// lpminst : ILPM EOL { genLpm($1, 0, NULL, FALSE); } | ILPM registername COMMA indirectaddr EOL { genLpm($1, $2, &$4, TRUE); } /// Error recovery ////////////////////////////////////////// | ILPM error EOL { error(E_INVALID_REGISTER_SPEC); } ; //////////////////////////////////////////////////////////////////////////// // // registername := REGISTER | SYMBOL // //////////////////////////////////////////////////////////////////////////// // // Handle registers: r0 - r31 // //////////////////////////////////////////////////////////////////////////// registername : REGISTER | SYMBOL { if($1->isdefine) $$=$1->reg; else { $$=-1; errorin(E_INVALID_REGISTER_SPEC); } } ; //////////////////////////////////////////////////////////////////////////// // // lable := SYMBOL COLON // | e // //////////////////////////////////////////////////////////////////////////// // // SYMBOL COLON = Create new label // //////////////////////////////////////////////////////////////////////////// label : SYMBOL COLON { doLab($1); } | e ; //////////////////////////////////////////////////////////////////////////// // // directive := DEF SYMBOL EQUAL REGISTER EOL // | DEF SYMBOL EQUAL SYMBOL EOL // | EQU SYMBOL EQUAL expr EOL // | DB {doAdb();} byteexprlist EOL // | DW {doAdw();} wordexprlist EOL // | ORG expr EOL // | ALIGN expr EOL // | CSEG EOL // | DSEG EOL // | ESEG EOL // | BYTE expr EOL // | SET SYMBOL EQUAL expr EOL // | MACRODEF // | DEVICE SYMBOL EOL // //////////////////////////////////////////////////////////////////////////// // // 'directive' insert assembler directives // //////////////////////////////////////////////////////////////////////////// directive : DEF SYMBOL EQUAL REGISTER EOL {doDef($2,$4);} | DEF SYMBOL EQUAL SYMBOL EOL {doDef($2,$4); } | EQU SYMBOL EQUAL expr EOL {doEqu($2,&$4); } | DB {doAdb();} byteexprlist EOL {/*XXX*/ } | DW {doAdw();} wordexprlist EOL { } | ORG expr EOL {doOrg(&$2); } | ALIGN expr EOL {doAlign(&$2); } | CSEG EOL { } | DSEG EOL { } | ESEG EOL { } | BYTE expr EOL {doByt(&$2); } | SET SYMBOL EQUAL expr EOL {doSet($2,&$4); } | MACRODEF { } | DEVICE SYMBOL EOL {doDev($2); } /// Error recovery ////////////////////////////////////////// | DEF error EOL { error(E_EXPECTED_ID_REG); } | EQU error EOL { error(E_EXPECTED_ID_EXPR); } | DB error EOL { error(E_EXPECTED_VALLIST); } | DW error EOL { error(E_EXPECTED_VALLIST); } | ORG error EOL { error(E_EXPECTED_VAL_LABEL); } | ALIGN error EOL { error(E_EXPECTED_VAL_LABEL); } | CSEG error EOL { error(E_EXPECTED_NOARGS); } | DSEG error EOL { error(E_EXPECTED_NOARGS); } | ESEG error EOL { error(E_EXPECTED_NOARGS); } | BYTE error EOL { error(E_EXPECTED_VAL_LABEL); } | SET error EOL { error(E_EXPECTED_ID_EXPR); } | DEVICE error EOL { error(E_EXPECTED_DEVICE); } ; //////////////////////////////////////////////////////////////////////////// // // indirectaddr := MINUS REGXYZ // | REGXYZ // | REGXYZ PLUS // | REGXYZ PLUS expr // //////////////////////////////////////////////////////////////////////////// // // There are 4 different forms of indirect addressing: // // "-Z", "Z", "Z+" and "Z+offset" // //////////////////////////////////////////////////////////////////////////// indirectaddr : MINUS REGXYZ {$$.regno=$2;$$.plus=2;$$.disp=0;} | REGXYZ {$$.regno=$1;$$.plus=0;$$.disp=0;} | REGXYZ PLUS {$$.regno=$1;$$.plus=1;$$.disp=0;} | REGXYZ PLUS expr { $$.regno = $1; $$.plus=1;$$.disp=1;$$.offset=$3;} ; //////////////////////////////////////////////////////////////////////////// // // byteexprlist := byteexprlist COMMA expr // | expr // // wordexprlist := wordexprlist COMMA expr // | expr // //////////////////////////////////////////////////////////////////////////// // // List of bytes and words for .db and .dw respectively // //////////////////////////////////////////////////////////////////////////// byteexprlist : byteexprlist COMMA byteelement | byteelement ; byteelement : STRING {doAdb($1); } | expr {doAdb(&$1);} ; wordexprlist : wordexprlist COMMA expr {doAdw(&$3);} | expr {doAdw(&$1);} ; //////////////////////////////////////////////////////////////////////////// // // expr := ... // //////////////////////////////////////////////////////////////////////////// // // Constant expressions with 'C' precedence // //////////////////////////////////////////////////////////////////////////// expr : composite_expr ; primary_expr : INTEGER | COUNTER | SYMBOL {$$.valid=$1->valid; $$.value=$1->value +$1->islabel*$1->macrolabel* (yyoffset *($1->segment==SEGMENT_CODE)) +$1->islabel*$1->macrolabel* (yydataoffset*($1->segment==SEGMENT_DATA)) +$1->islabel*$1->macrolabel* (yyeromoffset*($1->segment==SEGMENT_EEPROM));} | LPAR expr RPAR { $$=$2; } | FUNCTION LPAR expr RPAR { genFun($1, &$3, &$$); } ; unary_expr : MINUS unary_expr { oprUna(OP_MINUS, &$2, &$$); } | WAVE unary_expr { oprUna(OP_WAVE , &$2, &$$); } | NOT unary_expr { oprUna(OP_NOT , &$2, &$$); } | primary_expr ; mult_expr : unary_expr | mult_expr STAR unary_expr { oprBin(&$1,OP_STAR , &$3, &$$); } | mult_expr DIV unary_expr { oprBin(&$1,OP_DIV , &$3, &$$); } | mult_expr MOD unary_expr { oprBin(&$1,OP_MOD , &$3, &$$); } ; additive_expr : mult_expr | additive_expr PLUS mult_expr { oprBin(&$1,OP_PLUS , &$3, &$$); } | additive_expr MINUS mult_expr { oprBin(&$1,OP_MINUS , &$3, &$$); } ; shift_expr : additive_expr | shift_expr LS additive_expr { oprBin(&$1,OP_LS , &$3, &$$); } | shift_expr RS additive_expr { oprBin(&$1,OP_RS , &$3, &$$); } ; relational_expr : shift_expr | relational_expr LESS shift_expr { oprBin(&$1,OP_LESS , &$3, &$$); } | relational_expr GREAT shift_expr { oprBin(&$1,OP_GREAT , &$3, &$$); } | relational_expr LE shift_expr { oprBin(&$1,OP_LE , &$3, &$$); } | relational_expr GE shift_expr { oprBin(&$1,OP_GE , &$3, &$$); } ; equality_expr : relational_expr | equality_expr EQ relational_expr { oprBin(&$1,OP_EQ , &$3, &$$); } | equality_expr NE relational_expr { oprBin(&$1,OP_NE , &$3, &$$); } ; AND_expression : equality_expr | AND_expression AND equality_expr { oprBin(&$1,OP_AND , &$3, &$$); } ; exclusive_OR : AND_expression | exclusive_OR XOR AND_expression { oprBin(&$1,OP_XOR , &$3, &$$); } ; inclusive_OR : exclusive_OR | inclusive_OR OR exclusive_OR { oprBin(&$1,OP_OR , &$3, &$$); } ; logical_AND : inclusive_OR | logical_AND ANDAND inclusive_OR { oprBin(&$1,OP_ANDAND, &$3, &$$); } ; logical_OR : logical_AND | logical_OR OROR logical_AND { oprBin(&$1,OP_OROR , &$3, &$$); } ; composite_expr : logical_OR ; /// END OF FILE //////////////////////////////////////////////////////////////