gerbv  2.10.1-dev~93f1b5
amacro.c
Go to the documentation of this file.
1 /*
2  * gEDA - GNU Electronic Design Automation
3  * This files is a part of gerbv.
4  *
5  * Copyright (C) 2000-2002 Stefan Petersen (spe@stacken.kth.se)
6  *
7  * $Id$
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
22  */
23 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 
33 #include "gerbv.h"
34 #include "gerb_file.h"
35 #include "amacro.h"
36 
37 /*
38  * Allocates a new instruction structure
39  */
40 static gerbv_instruction_t*
41 new_instruction(void) {
42  gerbv_instruction_t* instruction;
43 
44  instruction = (gerbv_instruction_t*)malloc(sizeof(gerbv_instruction_t));
45  if (instruction == NULL) {
46  free(instruction);
47  return NULL;
48  }
49 
50  memset(instruction, 0, sizeof(gerbv_instruction_t));
51 
52  return instruction;
53 } /* new_instruction */
54 
55 /*
56  * Allocates a new amacro structure
57  */
58 static gerbv_amacro_t*
59 new_amacro(void) {
60  gerbv_amacro_t* amacro;
61 
62  amacro = (gerbv_amacro_t*)malloc(sizeof(gerbv_amacro_t));
63  if (amacro == NULL) {
64  free(amacro);
65  return NULL;
66  }
67 
68  memset(amacro, 0, sizeof(gerbv_amacro_t));
69 
70  return amacro;
71 } /* new_amacro */
72 
73 /*
74  * Defines precedence of operators used in aperture macros
75  */
76 static int
77 math_op_prec(gerbv_opcodes_t math_op) {
78  switch (math_op) {
79  case GERBV_OPCODE_ADD:
80  case GERBV_OPCODE_SUB: return 1;
81  case GERBV_OPCODE_MUL:
82  case GERBV_OPCODE_DIV: return 2;
83  default:;
84  }
85 
86  return 0;
87 } /* math_op_prec */
88 
89 /*
90  * Operations on the operator stack. The operator stack is used in the
91  * "shunting yard algorithm" to achive precedence.
92  * Aperture macros has a very limited set of operators and matching precedence,
93  * so it is solved by a small array and an index to that array.
94  */
95 #define MATH_OP_STACK_SIZE 2
96 #define MATH_OP_PUSH(val) math_op[math_op_idx++] = val
97 #define MATH_OP_POP math_op[--math_op_idx]
98 #define MATH_OP_TOP (math_op_idx > 0) ? math_op[math_op_idx - 1] : GERBV_OPCODE_NOP
99 #define MATH_OP_EMPTY (math_op_idx == 0)
100 
101 /*
102  * Parses the definition of an aperture macro
103  */
104 gerbv_amacro_t*
105 parse_aperture_macro(gerb_file_t* fd) {
106  gerbv_amacro_t* amacro;
107  gerbv_instruction_t* ip = NULL;
108  int primitive = 0, c, found_primitive = 0;
109  gerbv_opcodes_t math_op[MATH_OP_STACK_SIZE];
110  int math_op_idx = 0;
111  int comma = 0; /* Just read an operator (one of '*+X/) */
112  int neg = 0; /* negative numbers succeding , */
113  unsigned char continueLoop = 1;
114  int equate = 0;
115 
116  amacro = new_amacro();
117 
118  memset(math_op, GERBV_OPCODE_NOP, sizeof(math_op));
119 
120  /*
121  * Get macroname
122  */
123  amacro->name = gerb_fgetstring(fd, '*');
124  c = gerb_fgetc(fd); /* skip '*' */
125  if (c == EOF) {
126  continueLoop = 0;
127  }
128 
129  /*
130  * Since I'm lazy I have a dummy head. Therefore the first
131  * instruction in all programs will be NOP.
132  */
133  amacro->program = new_instruction();
134  ip = amacro->program;
135 
136  while (continueLoop) {
137 
138  c = gerb_fgetc(fd);
139  switch (c) {
140  case '$':
141  if (found_primitive) {
142  ip->next = new_instruction(); /* XXX Check return value */
143  ip = ip->next;
144  ip->opcode = GERBV_OPCODE_PPUSH;
145  amacro->nuf_push++;
146  ip->data.ival = gerb_fgetint(fd, NULL);
147  comma = 0;
148  } else {
149  equate = gerb_fgetint(fd, NULL);
150  }
151  break;
152  case '*':
153  while (!MATH_OP_EMPTY) {
154  ip->next = new_instruction(); /* XXX Check return value */
155  ip = ip->next;
156  ip->opcode = MATH_OP_POP;
157  }
158  /*
159  * Check is due to some gerber files has spurious empty lines.
160  * (EagleCad of course).
161  */
162  if (found_primitive) {
163  ip->next = new_instruction(); /* XXX Check return value */
164  ip = ip->next;
165  if (equate) {
166  ip->opcode = GERBV_OPCODE_PPOP;
167  ip->data.ival = equate;
168  } else {
169  ip->opcode = GERBV_OPCODE_PRIM;
170  ip->data.ival = primitive;
171  }
172  equate = 0;
173  primitive = 0;
174  found_primitive = 0;
175  }
176  break;
177  case '=':
178  if (equate) {
179  found_primitive = 1;
180  }
181  break;
182  case ',':
183  if (!found_primitive) {
184  found_primitive = 1;
185  break;
186  }
187  while (!MATH_OP_EMPTY) {
188  ip->next = new_instruction(); /* XXX Check return value */
189  ip = ip->next;
190  ip->opcode = MATH_OP_POP;
191  }
192  comma = 1;
193  break;
194  case '+':
195  while ((!MATH_OP_EMPTY) && (math_op_prec(MATH_OP_TOP) >= math_op_prec(GERBV_OPCODE_ADD))) {
196  ip->next = new_instruction(); /* XXX Check return value */
197  ip = ip->next;
198  ip->opcode = MATH_OP_POP;
199  }
200  MATH_OP_PUSH(GERBV_OPCODE_ADD);
201  comma = 1;
202  break;
203  case '-':
204  if (comma) {
205  neg = 1;
206  comma = 0;
207  break;
208  }
209  while ((!MATH_OP_EMPTY) && (math_op_prec(MATH_OP_TOP) >= math_op_prec(GERBV_OPCODE_SUB))) {
210  ip->next = new_instruction(); /* XXX Check return value */
211  ip = ip->next;
212  ip->opcode = MATH_OP_POP;
213  }
214  MATH_OP_PUSH(GERBV_OPCODE_SUB);
215  break;
216  case '/':
217  while ((!MATH_OP_EMPTY) && (math_op_prec(MATH_OP_TOP) >= math_op_prec(GERBV_OPCODE_DIV))) {
218  ip->next = new_instruction(); /* XXX Check return value */
219  ip = ip->next;
220  ip->opcode = MATH_OP_POP;
221  }
222  MATH_OP_PUSH(GERBV_OPCODE_DIV);
223  comma = 1;
224  break;
225  case 'X':
226  case 'x':
227  while ((!MATH_OP_EMPTY) && (math_op_prec(MATH_OP_TOP) >= math_op_prec(GERBV_OPCODE_MUL))) {
228  ip->next = new_instruction(); /* XXX Check return value */
229  ip = ip->next;
230  ip->opcode = MATH_OP_POP;
231  }
232  MATH_OP_PUSH(GERBV_OPCODE_MUL);
233  comma = 1;
234  break;
235  case '0':
236  /*
237  * Comments in aperture macros are a definition starting with
238  * zero and ends with a '*'
239  */
240  if (!found_primitive && (primitive == 0)) {
241  /* Comment continues 'til next *, just throw it away */
242  free(gerb_fgetstring(fd, '*'));
243  c = gerb_fgetc(fd); /* Read the '*' */
244  break;
245  }
246  case '1':
247  case '2':
248  case '3':
249  case '4':
250  case '5':
251  case '6':
252  case '7':
253  case '8':
254  case '9':
255  case '.':
256  /*
257  * First number in an aperture macro describes the primitive
258  * as a numerical value
259  */
260  if (!found_primitive) {
261  primitive = (primitive * 10) + (c - '0');
262  break;
263  }
264  (void)gerb_ungetc(fd);
265  ip->next = new_instruction(); /* XXX Check return value */
266  ip = ip->next;
267  ip->opcode = GERBV_OPCODE_PUSH;
268  amacro->nuf_push++;
269  ip->data.fval = gerb_fgetdouble(fd);
270  if (neg)
271  ip->data.fval = -ip->data.fval;
272  neg = 0;
273  comma = 0;
274  break;
275  case '%':
276  gerb_ungetc(fd); /* Must return with % first in string
277  since the main parser needs it */
278  return amacro;
279  default:
280  /* Whitespace */
281  break;
282  }
283  if (c == EOF) {
284  continueLoop = 0;
285  }
286  }
287  free(amacro);
288  return NULL;
289 }
290 
291 void
292 free_amacro(gerbv_amacro_t* amacro) {
293  gerbv_amacro_t * am1, *am2;
294  gerbv_instruction_t *instr1, *instr2;
295 
296  am1 = amacro;
297  while (am1 != NULL) {
298  free(am1->name);
299  am1->name = NULL;
300 
301  instr1 = am1->program;
302  while (instr1 != NULL) {
303  instr2 = instr1;
304  instr1 = instr1->next;
305  free(instr2);
306  instr2 = NULL;
307  }
308 
309  am2 = am1;
310  am1 = am1->next;
311  free(am2);
312  am2 = NULL;
313  }
314 
315  return;
316 } /* free_amacro */
317 
318 void
319 print_program(gerbv_amacro_t* amacro) {
320  gerbv_instruction_t* ip;
321 
322  printf("Macroname [%s] :\n", amacro->name);
323  for (ip = amacro->program; ip != NULL; ip = ip->next) {
324  switch (ip->opcode) {
325  case GERBV_OPCODE_NOP: printf(" NOP\n"); break;
326  case GERBV_OPCODE_PUSH: printf(" PUSH %f\n", ip->data.fval); break;
327  case GERBV_OPCODE_PPOP: printf(" PPOP %d\n", ip->data.ival); break;
328  case GERBV_OPCODE_PPUSH: printf(" PPUSH %d\n", ip->data.ival); break;
329  case GERBV_OPCODE_ADD: printf(" ADD\n"); break;
330  case GERBV_OPCODE_SUB: printf(" SUB\n"); break;
331  case GERBV_OPCODE_MUL: printf(" MUL\n"); break;
332  case GERBV_OPCODE_DIV: printf(" DIV\n"); break;
333  case GERBV_OPCODE_PRIM: printf(" PRIM %d\n", ip->data.ival); break;
334  default: printf(" ERROR!\n"); break;
335  }
336  fflush(stdout);
337  }
338 } /* print_program */
Aperture macro parsing header info.
Header info for the file parsing support functions.
The main header file for the libgerbv library.
gerbv_opcodes_t
Definition: gerbv.h:127
@ GERBV_OPCODE_PPUSH
Definition: gerbv.h:130
@ GERBV_OPCODE_ADD
Definition: gerbv.h:132
@ GERBV_OPCODE_PPOP
Definition: gerbv.h:131
@ GERBV_OPCODE_PUSH
Definition: gerbv.h:129
@ GERBV_OPCODE_SUB
Definition: gerbv.h:133
@ GERBV_OPCODE_NOP
Definition: gerbv.h:128
@ GERBV_OPCODE_DIV
Definition: gerbv.h:135
@ GERBV_OPCODE_MUL
Definition: gerbv.h:134
@ GERBV_OPCODE_PRIM
Definition: gerbv.h:136