2 * gEDA - GNU Electronic Design Automation
3 * This files is a part of gerbv.
5 * Copyright (C) 2000-2002 Stefan Petersen (spe@stacken.kth.se)
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.
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.
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
25 \brief Aperture macro parsing functions
34 #include "gerb_file.h"
38 * Allocates a new instruction structure
40 static gerbv_instruction_t
*
43 gerbv_instruction_t
*instruction
;
45 instruction
= (gerbv_instruction_t
*)malloc(sizeof(gerbv_instruction_t
));
46 if (instruction
== NULL
) {
51 memset(instruction
, 0, sizeof(gerbv_instruction_t
));
54 } /* new_instruction */
58 * Allocates a new amacro structure
60 static gerbv_amacro_t
*
63 gerbv_amacro_t
*amacro
;
65 amacro
= (gerbv_amacro_t
*)malloc(sizeof(gerbv_amacro_t
));
71 memset(amacro
, 0, sizeof(gerbv_amacro_t
));
78 * Defines precedence of operators used in aperture macros
81 math_op_prec(gerbv_opcodes_t math_op
)
84 case GERBV_OPCODE_ADD
:
85 case GERBV_OPCODE_SUB
:
87 case GERBV_OPCODE_MUL
:
88 case GERBV_OPCODE_DIV
:
99 * Operations on the operator stack. The operator stack is used in the
100 * "shunting yard algorithm" to achive precedence.
101 * Aperture macros has a very limited set of operators and matching precedence,
102 * so it is solved by a small array and an index to that array.
104 #define MATH_OP_STACK_SIZE 2
105 #define MATH_OP_PUSH(val) math_op[math_op_idx++] = val
106 #define MATH_OP_POP math_op[--math_op_idx]
107 #define MATH_OP_TOP (math_op_idx > 0)?math_op[math_op_idx - 1]:GERBV_OPCODE_NOP
108 #define MATH_OP_EMPTY (math_op_idx == 0)
112 * Parses the definition of an aperture macro
115 parse_aperture_macro(gerb_file_t
*fd
)
117 gerbv_amacro_t
*amacro
;
118 gerbv_instruction_t
*ip
= NULL
;
119 int primitive
= 0, c
, found_primitive
= 0;
120 gerbv_opcodes_t math_op
[MATH_OP_STACK_SIZE
];
122 int comma
= 0; /* Just read an operator (one of '*+X/) */
123 int neg
= 0; /* negative numbers succeding , */
124 unsigned char continueLoop
= 1;
127 amacro
= new_amacro();
129 memset(math_op
, GERBV_OPCODE_NOP
, MATH_OP_STACK_SIZE
);
134 amacro
->name
= gerb_fgetstring(fd
, '*');
135 c
= gerb_fgetc(fd
); /* skip '*' */
141 * Since I'm lazy I have a dummy head. Therefore the first
142 * instruction in all programs will be NOP.
144 amacro
->program
= new_instruction();
145 ip
= amacro
->program
;
147 while(continueLoop
) {
152 if (found_primitive
) {
153 ip
->next
= new_instruction(); /* XXX Check return value */
155 ip
->opcode
= GERBV_OPCODE_PPUSH
;
157 ip
->data
.ival
= gerb_fgetint(fd
, NULL
);
160 equate
= gerb_fgetint(fd
, NULL
);
164 while (!MATH_OP_EMPTY
) {
165 ip
->next
= new_instruction(); /* XXX Check return value */
167 ip
->opcode
= MATH_OP_POP
;
170 * Check is due to some gerber files has spurious empty lines.
171 * (EagleCad of course).
173 if (found_primitive
) {
174 ip
->next
= new_instruction(); /* XXX Check return value */
177 ip
->opcode
= GERBV_OPCODE_PPOP
;
178 ip
->data
.ival
= equate
;
180 ip
->opcode
= GERBV_OPCODE_PRIM
;
181 ip
->data
.ival
= primitive
;
194 if (!found_primitive
) {
198 while (!MATH_OP_EMPTY
) {
199 ip
->next
= new_instruction(); /* XXX Check return value */
201 ip
->opcode
= MATH_OP_POP
;
206 while ((!MATH_OP_EMPTY
) &&
207 (math_op_prec(MATH_OP_TOP
) >= math_op_prec(GERBV_OPCODE_ADD
))) {
208 ip
->next
= new_instruction(); /* XXX Check return value */
210 ip
->opcode
= MATH_OP_POP
;
212 MATH_OP_PUSH(GERBV_OPCODE_ADD
);
221 while((!MATH_OP_EMPTY
) &&
222 (math_op_prec(MATH_OP_TOP
) >= math_op_prec(GERBV_OPCODE_SUB
))) {
223 ip
->next
= new_instruction(); /* XXX Check return value */
225 ip
->opcode
= MATH_OP_POP
;
227 MATH_OP_PUSH(GERBV_OPCODE_SUB
);
230 while ((!MATH_OP_EMPTY
) &&
231 (math_op_prec(MATH_OP_TOP
) >= math_op_prec(GERBV_OPCODE_DIV
))) {
232 ip
->next
= new_instruction(); /* XXX Check return value */
234 ip
->opcode
= MATH_OP_POP
;
236 MATH_OP_PUSH(GERBV_OPCODE_DIV
);
241 while ((!MATH_OP_EMPTY
) &&
242 (math_op_prec(MATH_OP_TOP
) >= math_op_prec(GERBV_OPCODE_MUL
))) {
243 ip
->next
= new_instruction(); /* XXX Check return value */
245 ip
->opcode
= MATH_OP_POP
;
247 MATH_OP_PUSH(GERBV_OPCODE_MUL
);
252 * Comments in aperture macros are a definition starting with
253 * zero and ends with a '*'
255 if (!found_primitive
&& (primitive
== 0)) {
256 /* Comment continues 'til next *, just throw it away */
257 gerb_fgetstring(fd
, '*');
258 c
= gerb_fgetc(fd
); /* Read the '*' */
272 * First number in an aperture macro describes the primitive
273 * as a numerical value
275 if (!found_primitive
) {
276 primitive
= (primitive
* 10) + (c
- '0');
279 (void)gerb_ungetc(fd
);
280 ip
->next
= new_instruction(); /* XXX Check return value */
282 ip
->opcode
= GERBV_OPCODE_PUSH
;
284 ip
->data
.fval
= gerb_fgetdouble(fd
);
286 ip
->data
.fval
= -ip
->data
.fval
;
291 gerb_ungetc(fd
); /* Must return with % first in string
292 since the main parser needs it */
308 free_amacro(gerbv_amacro_t
*amacro
)
310 gerbv_amacro_t
*am1
, *am2
;
311 gerbv_instruction_t
*instr1
, *instr2
;
314 while (am1
!= NULL
) {
318 instr1
= am1
->program
;
319 while (instr1
!= NULL
) {
321 instr1
= instr1
->next
;
337 print_program(gerbv_amacro_t
*amacro
)
339 gerbv_instruction_t
*ip
;
341 printf("Macroname [%s] :\n", amacro
->name
);
342 for (ip
= amacro
->program
; ip
!= NULL
; ip
= ip
->next
) {
344 case GERBV_OPCODE_NOP
:
347 case GERBV_OPCODE_PUSH
:
348 printf(" PUSH %f\n", ip
->data
.fval
);
350 case GERBV_OPCODE_PPOP
:
351 printf(" PPOP %d\n", ip
->data
.ival
);
353 case GERBV_OPCODE_PPUSH
:
354 printf(" PPUSH %d\n", ip
->data
.ival
);
356 case GERBV_OPCODE_ADD
:
359 case GERBV_OPCODE_SUB
:
362 case GERBV_OPCODE_MUL
:
365 case GERBV_OPCODE_DIV
:
368 case GERBV_OPCODE_PRIM
:
369 printf(" PRIM %d\n", ip
->data
.ival
);
377 } /* print_program */