Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /***********************************************************************
  2.  *
  3.  *  avra - Assembler for the Atmel AVR microcontroller series
  4.  *
  5.  *  Copyright (C) 1998-2004 Jon Anders Haugum, Tobias Weber
  6.  *
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; see the file COPYING.  If not, write to
  19.  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20.  *  Boston, MA 02111-1307, USA.
  21.  *
  22.  *
  23.  *  Authors of avra can be reached at:
  24.  *     email: jonah@omegav.ntnu.no, tobiw@suprafluid.com
  25.  *     www: http://sourceforge.net/projects/avra
  26.  *
  27.  *
  28.  * SourceForge.net: Detail:713798 Strings are not always correctly handled
  29.  * Change made by JEG 5-01-03
  30.  *
  31.  * global keyword is now .global to match common sytnax. TW 10-11-05
  32.  */
  33.  
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <ctype.h>
  38. #include <time.h>
  39.  
  40. #include "misc.h"
  41. #include "avra.h"
  42. #include "args.h"
  43.  
  44.  
  45. /* Special fgets. Like fgets, but with better check for CR, LF and FF and without the ending \n char */
  46. /* size must be >=2. No checks for s=NULL, size<2 or stream=NULL.  B.A. */
  47. char *fgets_new(struct prog_info *pi, char *s, int size, FILE *stream)
  48. {
  49.         int c;
  50.         char *ptr=s;
  51.         do {
  52.                 if((c=fgetc(stream))==EOF || IS_ENDLINE(c))     // Terminate at chr$ 10,12,13,0 and EOF
  53.                         break;
  54.         /*
  55.         ** concatenate lines terminated with \ only...
  56.         */
  57.         if (c == '\\')
  58.         {
  59.             /* only newline and cr may follow... */
  60.             if((c=fgetc(stream))==EOF)
  61.                 break;
  62.  
  63.             if(!IS_ENDLINE(c))              // Terminate at chr$ 10,12,13,0 and EOF
  64.             {
  65.                 *ptr++ = '\\';              // no concatenation, insert it
  66.             }
  67.             else
  68.             {
  69.                 // mit be additional LF (DOS)
  70.                 c=fgetc(stream);
  71.                 if (IS_ENDLINE(c))
  72.                     c=fgetc(stream);
  73.  
  74.                 if (c == EOF)
  75.                     break;
  76.             }
  77.         }
  78.  
  79.                 *ptr++=c;
  80.         } while(--size);
  81.         if((c==EOF) && (ptr==s))                                // EOF and no chars read -> that's all folks
  82.                 return NULL;
  83.         if(!size) {
  84.                 print_msg(pi, MSGTYPE_ERROR, "Line to long");
  85.                 return NULL;
  86.         }
  87.         *ptr=0;
  88.         if(c==12)                                               // Check for Formfeed (Bug [1462886])
  89.                 print_msg(pi, MSGTYPE_WARNING, "Found Formfeed char. Please remove it.");
  90.         if(c==13) {                                             // Check for CR LF sequence (DOS/ Windows line termination)
  91.                 if((c=fgetc(stream)) != 10) {
  92.                         ungetc(c,stream);
  93.                         print_msg(pi, MSGTYPE_WARNING, "Found CR (0x0d) without LF (0x0a). Please add a LF.");
  94.                 }
  95.         }
  96.         return s;
  97. }
  98.  
  99.  
  100. /*
  101.  * Parses given assembler file
  102.  */
  103.  
  104. int parse_file(struct prog_info *pi, char *filename)
  105. {
  106. #if debug == 1
  107.         printf("parse_file\n");
  108. #endif
  109.         int ok;
  110.         int loopok;
  111.         struct file_info *fi;
  112.         struct include_file *include_file;
  113.         ok = True;
  114.         if((fi=malloc(sizeof(struct file_info)))==NULL) {
  115.                 print_msg(pi, MSGTYPE_OUT_OF_MEM,NULL);
  116.                 return(False);
  117.         }
  118.         pi->fi = fi;
  119.         if(pi->pass == PASS_1) {
  120.                 if((include_file = malloc(sizeof(struct include_file)))==NULL) {
  121.                         print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
  122.                         free(fi);
  123.                         return(False);
  124.                 }
  125.                 include_file->next = NULL;
  126.                 if(pi->last_include_file) {
  127.                         pi->last_include_file->next = include_file;
  128.                         include_file->num = pi->last_include_file->num + 1;
  129.                 } else {
  130.                         pi->first_include_file = include_file;
  131.                         include_file->num = 0;
  132.                 }
  133.                 pi->last_include_file = include_file;
  134.                 if((include_file->name = malloc(strlen(filename) + 1))==NULL) {
  135.                         print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
  136.                         free(fi);
  137.                         return(False);
  138.                 }
  139.                 strcpy(include_file->name, filename);
  140.         } else { // PASS 2
  141.                 for(include_file = pi->first_include_file; include_file; include_file = include_file->next) {
  142.                         if(!strcmp(include_file->name, filename))
  143.                                 break;
  144.                 }
  145.         }
  146.         if(!include_file) {
  147.                 print_msg(pi, MSGTYPE_ERROR, "Internal assembler error");
  148.                 free(fi);
  149.                 return(False);
  150.         }
  151.         fi->include_file = include_file;
  152.         fi->line_number = 0;
  153.         fi->exit_file = False;
  154. #if debug == 1
  155.         printf("Opening %s\n",filename);
  156. #endif
  157.         if((fi->fp = fopen(filename, "r"))==NULL) {
  158.                 perror(filename);
  159.                 free(fi);
  160.                 return(False);
  161.         }
  162.         loopok = True;
  163.         while(loopok && !fi->exit_file) {
  164.                 if(fgets_new(pi,fi->buff, LINEBUFFER_LENGTH, fi->fp)) {
  165.                         fi->line_number++;
  166.                         pi->list_line = fi->buff;
  167.                         ok = parse_line(pi, fi->buff);
  168. #if debug == 1
  169.                         printf("parse_line was %i\n", ok);
  170. #endif
  171.                         if(ok) {
  172.                                 if((pi->pass == PASS_2) && pi->list_line && pi->list_on)
  173.                                         fprintf(pi->list_file, "         %s\n", pi->list_line);
  174.                                 if(pi->error_count >= pi->max_errors) {
  175.                                         print_msg(pi, MSGTYPE_MESSAGE, "Maximum error count reached. Exiting...");
  176.                                         loopok = False;
  177.                                 }
  178.                         } else {
  179.                                 loopok = False;
  180.                         }
  181.                 } else {
  182.                         loopok = False;
  183.                         if(!feof(fi->fp)) {
  184.                                 ok = False;
  185.                                 perror(filename);
  186.                         }
  187.                 }
  188.         }
  189.         fclose(fi->fp);
  190.         free(fi);
  191.         return(ok);
  192. }
  193.  
  194.  
  195. /****************************************************************************
  196.  *
  197.  * function parse_line
  198.  *
  199.  * Parses one line
  200.  *
  201.  ****************************************************************************/
  202.  
  203.  
  204. int parse_line(struct prog_info *pi, char *line)
  205. {
  206.         char *ptr=NULL;
  207.         int k;
  208.         int flag=0, i;
  209.         int global_label = False;
  210.         char temp[LINEBUFFER_LENGTH];
  211.         struct label *label = NULL;
  212.         struct macro_call *macro_call;
  213.  
  214.         while(IS_HOR_SPACE(*line)) line++;                      /* At first remove leading spaces / tabs */
  215.         if(IS_END_OR_COMMENT(*line))                            /* Skip comment line or empty line */
  216.                 return(True);
  217.                                                                 /* Filter out .stab debugging information */
  218.                                                                 /* .stabs sometimes contains colon : symbol - might be interpreted as label */
  219.         if(*line == '.') {                                      /* minimal slowdown of existing code */
  220.                 if(strncmp(temp,".stabs ",7) == 0 ) {           /* compiler output is always lower case */
  221.                         strcpy(temp,line);                      /* TODO : Do we need this temp variable ? Please check */
  222.                         return parse_stabs( pi, temp );
  223.                 }
  224.                 if(strncmp(temp,".stabn ",7) == 0 ) {
  225.                         strcpy(temp,line);
  226.                         return parse_stabn( pi, temp );
  227.                 }
  228.         }
  229.                                                                 /* Meta information translation */
  230.         ptr=line;
  231.         k=0;
  232.         while((ptr=strchr(ptr, '%')) != NULL) {
  233.                 if(!strncmp(ptr, "%MINUTE%", 8) ) {             /* Replacement always shorter than tag -> no length check */
  234.                         k=strftime(ptr,3,"%M", localtime(&pi->time));
  235.                         strcpy(ptr+k,ptr+8);
  236.                         ptr+=k;
  237.                         continue;
  238.                 }
  239.                 if(!strncmp(ptr, "%HOUR%", 6) ) {                      
  240.                         k=strftime(ptr,3,"%H", localtime(&pi->time));
  241.                         strcpy(ptr+k,ptr+6);
  242.                         ptr+=k;
  243.                         continue;
  244.                 }
  245.                 if(!strncmp(ptr, "%DAY%", 5) ) {
  246.                         k=strftime(ptr,3,"%d", localtime(&pi->time));
  247.                         strcpy(ptr+k,ptr+5);
  248.                         ptr+=k;
  249.                         continue;
  250.                 }
  251.                 if(!strncmp(ptr, "%MONTH%", 7) ) {
  252.                         k=strftime(ptr,3,"%m", localtime(&pi->time));
  253.                         strcpy(ptr+k,ptr+7);
  254.                         ptr+=k;
  255.                         continue;
  256.                 }
  257.                 if(!strncmp(ptr, "%YEAR%", 6) ) {
  258.                         k=strftime(ptr,5,"%Y", localtime(&pi->time));
  259.                         strcpy(ptr+k,ptr+6);
  260.                         ptr+=k;
  261.                         continue;
  262.                 }
  263.                 ptr++;
  264.         }
  265.  
  266. //      if(pi->pass == PASS_2)          // TODO : Test
  267. //              strcpy(pi->list_line, line);
  268.  
  269.         strcpy(pi->fi->scratch,line);
  270.  
  271.         for(i = 0; IS_LABEL(pi->fi->scratch[i]) || (pi->fi->scratch[i] == ':'); i++)
  272.                 if(pi->fi->scratch[i] == ':') { /* it is a label */
  273.                         pi->fi->scratch[i] = '\0';
  274.                         if(pi->pass == PASS_1) {
  275.                                 for(macro_call = pi->macro_call; macro_call; macro_call = macro_call->prev_on_stack) {
  276.                                         for(label = pi->macro_call->first_label; label; label = label->next) {
  277.                                                 if(!nocase_strcmp(label->name, &pi->fi->scratch[0])) {
  278.                                                         print_msg(pi, MSGTYPE_ERROR, "Can't redefine local label %s", &pi->fi->scratch[0]);
  279.                                                         break;
  280.                                                 }
  281.                                         }
  282.                                 }
  283.                                 if(test_label(pi,&pi->fi->scratch[0],"Can't redefine label %s")!=NULL)
  284.                                         break;
  285.                                 if(test_variable(pi,&pi->fi->scratch[0],"%s have already been defined as a .SET variable")!=NULL)
  286.                                         break;
  287.                                 if(test_constant(pi,&pi->fi->scratch[0],"%s has already been defined as a .EQU constant")!=NULL)
  288.                                         break;
  289.                                 label = malloc(sizeof(struct label));
  290.                                 if(!label) {
  291.                                         print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
  292.                                         return(False);
  293.                                 }
  294.                                 label->next = NULL;
  295.                                 label->name = malloc(strlen(&pi->fi->scratch[0]) + 1);
  296.                                 if(!label->name) {
  297.                                         print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
  298.                                         return(False);
  299.                                 }
  300.                                 strcpy(label->name, &pi->fi->scratch[0]);
  301.                                 switch(pi->segment) {
  302.                                         case SEGMENT_CODE:
  303.                                                 label->value = pi->cseg_addr;
  304.                                                 break;
  305.                                         case SEGMENT_DATA:
  306.                                                 label->value = pi->dseg_addr;
  307.                                                 break;
  308.                                         case SEGMENT_EEPROM:
  309.                                                 label->value = pi->eseg_addr;
  310.                                                 break;
  311.                                 }
  312.                                 if(pi->macro_call && !global_label) {
  313.                                         if(pi->macro_call->last_label)
  314.                                                 pi->macro_call->last_label->next = label;
  315.                                         else
  316.                                                 pi->macro_call->first_label = label;
  317.                                         pi->macro_call->last_label = label;
  318.                                 } else {
  319.                                         if(pi->last_label)
  320.                                                 pi->last_label->next = label;
  321.                                         else
  322.                                                 pi->first_label = label;
  323.                                         pi->last_label = label;
  324.                                 }
  325.                         }
  326.                         i++;
  327.                         while(IS_HOR_SPACE(pi->fi->scratch[i]) && !IS_END_OR_COMMENT(pi->fi->scratch[i])) i++;
  328.                         if(IS_END_OR_COMMENT(pi->fi->scratch[i])) {
  329.                                 if((pi->pass == PASS_2) && pi->list_on) { // Diff tilpassing
  330.                                         fprintf(pi->list_file, "          %s\n", pi->list_line);
  331.                                         pi->list_line = NULL;
  332.                                 }
  333.                                 return(True);
  334.                         }
  335.                         strcpy(pi->fi->scratch, &pi->fi->scratch[i]);
  336.                         break;
  337.                 }
  338.  
  339. #if 0
  340.         if(pi->fi->scratch[0] == '.') {
  341. #else
  342.         if((pi->fi->scratch[0] == '.') || (pi->fi->scratch[0] == '#')) {
  343. #endif
  344.                 pi->fi->label = label;
  345.                 flag = parse_directive(pi);
  346.                 if((pi->pass == PASS_2) && pi->list_on && pi->list_line) { // Diff tilpassing
  347.                         fprintf(pi->list_file, "          %s\n", pi->list_line);
  348.                         pi->list_line = NULL;
  349.                 }
  350.                 return(flag);
  351.         } else {
  352.                 return parse_mnemonic(pi);
  353.         }
  354. }
  355.  
  356.  
  357. /*
  358.  * Get the next token, and terminate the last one.
  359.  * Termination identifier is specified.
  360.  */
  361.  
  362. char *get_next_token(char *data, int term)
  363. {
  364.         int i = 0, j, anti_comma = False;
  365.         switch(term) {
  366.                 case TERM_END:
  367. //                      while(!IS_END_OR_COMMENT(data[i])) i++;         Problems with 2. operand == ';'
  368.                         while( ((data[i] != ',') || anti_comma) && !(((data[i] == ';') && !anti_comma) || IS_ENDLINE(data[i])) ) {
  369.                                 if((data[i] == '\'') || (data[i] == '"'))
  370.                                         anti_comma = anti_comma ? False : True;
  371.                                 i++;
  372.                         }
  373.                         break;
  374.                 case TERM_SPACE:
  375.                         while(!IS_HOR_SPACE(data[i]) && !IS_END_OR_COMMENT(data[i])) i++;
  376.                         break;
  377.                 case TERM_DASH:
  378.                         while((data[i] != '-') && !IS_END_OR_COMMENT(data[i])) i++;
  379.                         break;
  380.                 case TERM_COLON:
  381.                         while((data[i] != ':') && !IS_ENDLINE(data[i])) i++;
  382.                         break;
  383.                 case TERM_DOUBLEQUOTE:
  384.                         while((data[i] != '"') && !IS_ENDLINE(data[i])) i++;
  385.                         break;
  386.                 case TERM_COMMA:
  387.                         while(((data[i] != ',') || anti_comma) && !(((data[i] == ';') && !anti_comma) || IS_ENDLINE(data[i])) ) {
  388.                                 if((data[i] == '\'') || (data[i] == '"'))
  389.                                         anti_comma = anti_comma ? False : True;
  390.                                 i++;
  391.                         }
  392.                         break;
  393.                 case TERM_EQUAL:
  394.                         while((data[i] != '=') && !IS_END_OR_COMMENT(data[i])) i++;
  395.                         break;
  396.         }
  397.         if(IS_END_OR_COMMENT(data[i])) {
  398.                 data[i--] = '\0';
  399.                 while(IS_HOR_SPACE(data[i])) data[i--] = '\0';
  400.                 return(0);
  401.         }
  402.         j = i - 1;
  403.         while(IS_HOR_SPACE(data[j])) data[j--] = '\0';
  404.         data[i++] = '\0';
  405.         while(IS_HOR_SPACE(data[i]) && !IS_END_OR_COMMENT(data[i])) i++;
  406.         if(IS_END_OR_COMMENT(data[i]))
  407.                 return(0);
  408.         return(&data[i]);
  409. }
  410.  
  411. /* end of parser.c */
  412.  
  413.