Pristine Ack-5.5
[Ack-5.5.git] / util / ceg / assemble / obj_assemble / assemble.c
1 #include <ctype.h>
2 #include <system.h>
3 #include <stdio.h>
4 #if __STDC__
5 #include <stdarg.h>
6 extern error(char *, ...);
7 #else
8 #include <varargs.h>
9 #endif
10 #include "as.h"
11 #include "const.h"
12
13
14 /* This file contains the routine assemble(). Assemble() cuts an
15  * assembly instruction in a label, a mnemonic and several operands.
16  * For a mnemonic,label and operands it calls table writer defined 
17  * routines, process_mnemonic() * process_label() and process_operand(), 
18  * to give the table writer the oppurtunity to do something special.
19  * At the end assemble() calls the routine belonging to the mnemonic 
20  * with the supplied operands.
21  *     If the table writer has other expectations of assemble() he should
22  * write his own version.
23  *      Assemble parser the following instructions :
24  * INSTR ::= [ STRING ':']? [ STRING [ OPERAND ( ',' OPERAND)*]? ]?
25  * OPERAND ::= STRING [ '{' char* '}' |
26  *                      '(' char* ')' | 
27  *                      '[' char* ']'     ]?
28  * note : nested brackets are not recognized.
29  */
30
31
32 /* The following global varaibles are defined in the EM_parser.
33  */
34
35 extern char *mnemonic[];
36 extern int (*instruction[])(), n_mnems;
37
38 /* The struct t_operand must be defined by the table writer in "as.h".
39  * The constant MAX_OPERANDS is defined in "const.h"
40  * To change MAX_OPERANDS effectively, the last statement in 
41  * execute_mnem() must be changed.
42  */
43
44 struct t_operand operand[ MAX_OPERANDS];
45
46
47
48 char *skip_space(), *parse_label(), *parse_mnemonic(), *parse_operand(),
49      *skip_string(), *match_ch(), *Salloc(), *skip_operand();
50 int  label();
51
52
53 assemble( instr)
54         char *instr;
55 /* Break an assembly instruction down in a LABEL, MNEMONIC and OPERANDS.
56  */
57 {
58         char *ptr, *copy, *mnem;
59         int  n_ops = 0;
60
61         copy = ptr = Salloc( instr, strlen( instr)+1);
62
63         ptr = skip_space( ptr);
64         if  ( label( ptr))  {     /* Look for a label */
65                 ptr = parse_label( ptr);
66                 if  ( *ptr == '\0')  return;
67         }
68
69         ptr = parse_mnemonic( ptr, &mnem);
70         while  ( *ptr != '\0')  {  /* parse operans */
71                 if ( n_ops++ == MAX_OPERANDS) 
72                         error( "to many operands\n");
73                 ptr = parse_operand( ptr, n_ops, instr);
74         }
75
76         execute_mnemonic( mnem);   /* Execute the assembler instruction */
77         free( copy);
78 }
79
80
81 int label( ptr)
82         char *ptr;
83 {
84         ptr = skip_string( ptr);
85         ptr = skip_space( ptr);
86         return( *ptr == ':');
87 }
88
89
90 char *parse_label( ptr)
91         char *ptr;
92 {
93         char *lab = ptr;
94
95         ptr = skip_string( ptr);
96         if  ( *ptr == ':') 
97                 *ptr++ = '\0';
98         else {
99                 *ptr++ = '\0';
100                 ptr = skip_space( ptr);
101                 ptr++;          /* skip ':' */
102         }
103         handle_label( lab);
104         ptr = skip_space( ptr);
105         return( ptr);
106 }
107
108
109 char *parse_mnemonic( ptr, mnem)
110         char *ptr, **mnem;
111 {
112         *mnem = ptr;
113         ptr = skip_string( ptr);
114         if  ( *ptr != '\0') {
115                 *ptr++ = '\0';
116                 ptr = skip_space( ptr);
117         }
118         return( ptr);
119 }
120
121
122 char *parse_operand( ptr, n_ops, instr)
123         char *ptr, *instr;
124         int  n_ops;
125 {
126         char *op = ptr,
127              *last;
128
129         ptr = skip_operand( ptr, instr);
130         for( last=ptr-1; isspace( *last); last--) 
131                 ;
132         if ( *ptr == ',')  {
133                 ptr = skip_space( ptr + 1);
134         }
135         *(last+1) = '\0';
136                 
137         process_operand( op, &operand[ n_ops-1]);
138         return( ptr);
139 }
140
141
142 char *skip_operand( ptr, instr)
143         char *ptr, *instr;
144 {
145         while  ( *ptr != ',' && *ptr != '\0')  {
146                 switch  ( *ptr)  {
147                   case '{' : ptr = match_ch( '}', ptr, instr);
148                              break;
149                   case '(' : ptr = match_ch( ')', ptr, instr);
150                              break;
151                   case '[' : ptr = match_ch( ']', ptr, instr);
152                              break;
153                 }
154                 ptr++;
155         }
156         return( ptr);
157 }
158
159
160 char *match_ch( c, str, instr)
161         char c, *str, *instr;
162 {
163         char *ptr, *strindex();
164
165         ptr = strindex( str, c);
166         if  ( ptr == 0)  {
167                 error( "syntax error in %s : %c expected\n", instr, c);
168                 return( str);
169         }
170         else
171                 return( ptr);
172 }
173
174
175 char *skip_string( ptr)
176         char *ptr;
177 {
178         while  ( *ptr != '\0' && !isspace( *ptr) && *ptr != ':')
179                 ptr++;
180         return( ptr);
181 }
182
183
184 char *skip_space( ptr)
185 char *ptr;
186 {
187         while ( isspace( *ptr) )
188                 ptr++;
189         return( ptr);
190 }
191
192
193 /*** Execution **************************************************************/
194
195
196 execute_mnemonic( mnem)
197 char *mnem;
198
199 /* Find the function by "mnem" and execute it.
200  */
201 {
202         int low, mid, high, rel;
203
204         process_mnemonic( mnem);
205
206         low = 0;
207         high = n_mnems-1;
208
209         while ( TRUE) {
210                 mid = ( low + high) / 2;
211                 rel = strcmp(mnem, mnemonic[ mid]);
212
213                 if ( rel == 0 )
214                         break;
215                 else if ( high == low) {
216                         error( "can't find %s", mnem);
217                         return;
218                 }
219                 else if ( rel < 0)
220                         high = mid;
221                 else
222                         /* watch it, mid is truncated */
223                         low = ( mid == low ? low + 1: mid);
224         }
225         ( *( instruction[ mid]))( &operand[0], &operand[1], &operand[2], 
226                                   &operand[3]);
227 }
228
229
230 /*** Error ****************************************************************/
231
232 #if __STDC__
233 /*VARARGS*/
234 error(char *fmt, ...)
235 {
236         va_list args;
237         extern int yylineno;
238         extern int nerrors;
239
240         va_start(args, fmt);
241                 fprint( STDERR, "ERROR in line %d :     ", yylineno);
242                 doprnt( STDERR, fmt, args);
243                 fprint( STDERR, "\n");
244         va_end(args);
245         nerrors++;
246 }
247 #else
248 /*VARARGS*/
249 error(va_alist)
250         va_dcl
251 {
252         char *fmt;
253         va_list args;
254         extern int yylineno;
255         extern int nerrors;
256
257         va_start(args);
258                 fmt = va_arg(args, char *);
259                 fprint( STDERR, "ERROR in line %d :     ", yylineno);
260                 doprnt( STDERR, fmt, args);
261                 fprint( STDERR, "\n");
262         va_end(args);
263         nerrors++;
264 }
265 #endif