2 This file is part of the software library CADLIB written by Conrad Ziesler
3 Copyright 2003, Conrad Ziesler, all rights reserved.
5 *************************
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* scanner.c, support for scanning text, tokenifies input, uses file_readline
26 /* goal: support cad tool file reading
28 cad tool requirements: large file size, regular file handling
29 needs to: minimize memory allocations, prevent memory leaks
30 should provide: allow higher up layers to never need to call strdup
31 unless they really want to. that is we alloc in place
46 /**** standard error and warning reporting ************/
48 static void parse_warn_error(int which
, scanner_t
*scan
, char *fmt
, va_list va
)
51 static char buf
[4096];
52 card_t
*c
=scan
->errcard
;
53 deck_t
*d
=scan
->errdeck
;
55 char *warnerr
="WARNING";
61 if (scan
->inputp
!=NULL
)
63 line
=scan
->inputp
->line
;
64 file
=scan
->inputp
->index
;
67 else { line
=d
->line
.line
; file
=d
->line
.fileindex
; }
69 if(which
) warnerr
="ERROR";
73 sprintf(bp
,"line %i: %s: near %s : ",line
,warnerr
,c
->str
);
74 else sprintf(bp
,"line %i: %s: :",line
,warnerr
);
77 for(c
=d
->card
;c
!=NULL
;c
=c
->next
)
80 if(bp
>(buf
+sizeof(buf
)-256)) assert(0);
81 if(c
->val
!=NULL
)sprintf(bp
,"%s=%s ",c
->str
,c
->val
);
82 else sprintf(bp
,"%s ",c
->str
);
85 sprintf(bp
,"\n --> %s",fmt
);
90 if(scan
->warnfunc
!=NULL
)
91 { scan
->warnfunc(scan
,buf
,va
); return; }
93 if(scan
->errfunc
!=NULL
)
94 scan
->errfunc(scan
,buf
,va
);
97 void parse_error (scanner_t
*scan
, char *fmt
, ...)
101 parse_warn_error(1,scan
,fmt
,va
);
105 void parse_warn (scanner_t
*scan
, char *fmt
, ...)
109 parse_warn_error(0,scan
,fmt
,va
);
113 void scanner_def_err(scanner_t
*scan
, char *fmt
, va_list vp
)
115 vfprintf(stderr
,fmt
,vp
);
120 /***** private helper functions *********/
123 static void free_cards(scanner_t
*scan
, card_t
*c
)
135 static void deck_free(scanner_t
*scan
, deck_t
*deck
)
142 free_cards(tofree
->card
);
149 static deck_t
*new_deck(scanner_t
*scan
)
152 d
=memory_alloc(&(scan
->strmem
),sizeof(deck_t
));
156 d
->line
=scanner_current_file_line(scan
);
161 void scanner_add_tokens(scanner_t
*scan
, tokenmap_t
*map
)
164 if(scan
->sectp
==NULL
)assert(0);
167 for(i
=0;map
[i
].str
!=NULL
;i
++)
168 names_add(scan
->sectp
->tokenizer
,map
[i
].token
,map
[i
].str
);
172 void scanner_reset_tokens(scanner_t
*scan
)
174 if(scan
->sectp
!=NULL
)
176 names_free(scan
->sectp
->tokenizer
);
177 scan
->sectp
->tokenizer
=names_new();
184 void scanner_input_new(scanner_t
*scan
, file_spec_p file
)
187 p
=malloc(sizeof(scanner_input_t
));
188 if(p
!=NULL
)memset(p
,0,sizeof(scanner_input_t
));
193 if(scan
->allinputs
==NULL
)
196 p
->index
=scan
->allinputs
->index
+1;
197 p
->next
=scan
->allinputs
;
199 p
->back
=scan
->inputp
;
206 void scanner_input_newfp(scanner_t
*scan
, void *fp
)
209 p
=malloc(sizeof(scanner_input_t
));
210 if(p
!=NULL
)memset(p
,0,sizeof(scanner_input_t
));
214 if(scan
->allinputs
==NULL
)
217 p
->index
=scan
->allinputs
->index
+1;
218 p
->next
=scan
->allinputs
;
220 p
->back
=scan
->inputp
;
225 void scanner_sect_new(scanner_t
*scan
, scanner_def_t
*defs
, tokenmap_t
*map
)
227 scanner_sect_t
*sect
;
229 sect
=malloc(sizeof(scanner_sect_t
));
230 if(sect
!=NULL
)memset(sect
,0,sizeof(scanner_sect_t
));
233 sect
->tokenizer
=names_new();
242 sect
->back
=scan
->sectp
;
244 scanner_add_tokens(scan
,map
);
248 void scanner_input_release(scanner_t
*scan
) /* release top of stack */
251 if((p
=scan
->inputp
)!=NULL
)
253 scan
->inputp
=scan
->inputp
->back
;
254 /* we don't free, we keep on list,
260 void scanner_sect_release(scanner_t
*scan
) /* release top of stack */
264 if((p
=scan
->sectp
)!=NULL
)
266 scan
->sectp
=scan
->sectp
->back
;
267 names_free(p
->tokenizer
);
272 void scanner_init(scanner_t
*scan
)
274 memory_init(&(scan
->strmem
));
276 scan
->allinputs
=NULL
;
280 scan
->errfunc
=scanner_def_err
;
281 scan
->warnfunc
=scanner_def_err
;
285 void scanner_free_all(scanner_t
*scan
)
287 memory_freeall(&(scan
->strmem
));
290 void scanner_release(scanner_t
*scan
)
292 scanner_input_t
*p
,*np
;
294 while(scan
->sectp
!=NULL
)
295 scanner_sect_release(scan
);
297 while(scan
->inputp
!=NULL
)
298 scanner_input_release(scan
);
300 for(p
=scan
->allinputs
;p
!=NULL
;p
=np
)
303 if(p
->file_fp
!=NULL
) fclose(p
->file_fp
);
307 scanner_free_all(scan
);
313 int scanner_checkvalid(deck_t
*d
, int qty
)
318 for(i
=0,c
=d
->card
;c
!=NULL
;c
=c
->next
,i
++)
332 /***** the actual scanner routines *****/
335 static char *skip_stuff(char *toskip
, char *str
, int sense
)
339 for(cp
=str
;cp
[0]!=0;cp
++)
341 for(ws
=toskip
;ws
[0]!=0;ws
++)
342 if(ws
[0]==cp
[0]) break;
343 if( (ws
[0]==0) && (sense
==0) ) break; /* no toskip char found */
344 if( (ws
[0]!=0) && (sense
!=0) ) break; /* toskip char found */
349 static void skip_space(scanner_t
*scan
, char **p
)
350 { *p
=skip_stuff(scan
->sectp
->def
->whitespace
,*p
,0); }
353 static void skip_nonspace(scanner_t
*scan
, char **p
)
354 { *p
=skip_stuff(scan
->sectp
->def
->whitespace
,*p
,1); }
357 static void skip_nonspace_quote(scanner_t
*scan
, char **p
)
359 scanner_def_t
*def
=scan
->sectp
->def
;
364 /* this is set to 2 origninally since first iteration hits same character */
365 if(cp
[0]==def
->quote_char
)quote
=2;
368 if(cp
[0]==def
->quote_char
){ quote
--; if(quote
==0){ if(cp
[0]!=0)cp
++; break; } }
371 for(ws
=def
->whitespace
;ws
[0]!=0;ws
++)
372 if(ws
[0]==cp
[0]) break;
373 if( (ws
[0]!=0) ) break; /* whitespace char found */
381 static int astreq(char *s
, char *lng
)
386 if(lng
[0]==0)return -1;
387 if(s
[0]!=lng
[0])return 1;
395 static card_t
*make_card(scanner_t
*scan
, char *p1
, char *p2
, char *p3
, char *p4
)
397 scanner_def_t
*def
=scan
->sectp
->def
;
402 if( (p1
!=NULL
) && (p2
!=NULL
)) l1
=p2
-p1
;
403 if( (p3
!=NULL
) && (p4
!=NULL
)) l2
=p4
-p3
;
407 lc
=strlen(def
->eol_continue
);
409 if(p1
[0]==0) return NULL
; /* nothing here */
412 if(!astreq(def
->eol_continue
,p2
-lc
))
416 memcpy(scan
->sectp
->eoline
,p1
,l1
-lc
);
417 scan
->sectp
->eoline
[l1
]=def
->assignment
;
418 scan
->sectp
->eoline
[l1
+1]=0;
419 scan
->sectp
->eolstring
=1;
426 if((p3
[0]==0)||(!astreq(def
->eol_continue
,p3
)))
428 memcpy(scan
->sectp
->eoline
,p1
,l1
);
429 scan
->sectp
->eoline
[l1
]=def
->assignment
;
430 scan
->sectp
->eoline
[l1
+1]=0;
431 scan
->sectp
->eolstring
=1;
436 c
=memory_alloc(&(scan
->strmem
),sizeof(card_t
)+l1
+l2
+2);
443 memcpy(c
->str
,p1
,l1
);
447 memcpy(c
->str
+l1
+1,p3
,l2
);
452 if(def
->convert_case
==PARSE_CASE_TOLOWER
)
453 for(i
=0;i
<(l1
+l2
+2);i
++)
454 c
->str
[i
]=tolower(c
->str
[i
]);
455 else if(def
->convert_case
==PARSE_CASE_TOUPPER
)
456 for(i
=0;i
<(l1
+l2
+2);i
++)
457 c
->str
[i
]=toupper(c
->str
[i
]);
460 if((def
->tokenize
[0]==0) || (!astreq(def
->tokenize
,c
->str
)))
461 c
->token
=names_check(scan
->sectp
->tokenizer
,c
->str
);
464 if(c
->val
[0]==scan
->sectp
->def
->quote_char
)c
->val
++;
473 int scanner_parse_line(scanner_t
*scan
)
475 scanner_def_t
*def
=scan
->sectp
->def
;
476 char *line
=scan
->sectp
->lbuf
;
478 char *p1
=NULL
,*p2
,*p3
,*p4
,*p5
,*p6
;
482 if(scan
->inputp
==NULL
)return 0;
483 if(scan
->inputp
->file_fp
!=NULL
) { if(feof(((FILE *)scan
->inputp
->file_fp
)))return 0; }
484 /* return 0; else { if(file_eof(scan->inputp->file)) return 0; } */
488 line
[sizeof(scan
->sectp
->lbuf
)-1]=0;
489 if(scan
->inputp
->file_fp
!=NULL
)
490 fgets(line
,sizeof(scan
->sectp
->lbuf
)-2,scan
->inputp
->file_fp
);
492 ; /* file_readline(scan->inputp->file,sizeof(scan->sectp->lbuf)-2,line); */
494 scan
->inputp
->line
++;
495 if(line
[0]==0)return 3;
498 if(dbg
)fprintf(stderr
,"line: %s",line
);
501 skip_space(scan
,&lp
);
503 if(lp
[0]==0) return 4;
505 if(!astreq(def
->commentstart
, lp
))return 5;
506 if(!astreq(def
->line_stop
, lp
)) return 0; /* stop scanning */
507 if(!astreq(def
->bol_continue
,lp
)) /* continue line */
508 { scan
->sectp
->line_cont
=1; lp
+=strlen(def
->bol_continue
); }
510 if(dbg
)fprintf(stderr
,"lp: %s",lp
);
514 if(lp
[l
-1]=='\n')lp
[l
-1]=0;
517 if(! (scan
->sectp
->line_cont
||scan
->sectp
->eolstring
)) /* make a new deck unless we are continuing */
521 if(scan
->sectp
->dhead
==NULL
)
522 { scan
->sectp
->dhead
=scan
->sectp
->dp
=dp
; }
524 { scan
->sectp
->dp
->next
=dp
; scan
->sectp
->dp
=dp
; }
526 scan
->sectp
->line_cont
=0;
528 /* continue last string if necessary */
529 if(scan
->sectp
->eolstring
)
531 p1
=scan
->sectp
->eoline
;
532 skip_space(scan
,&p1
);
534 skip_nonspace_quote(scan
,&p2
);
536 skip_space(scan
,&p3
);
538 skip_nonspace_quote(scan
,&p4
);
540 skip_space(scan
,&p5
);
542 skip_nonspace_quote(scan
,&p6
);
547 scan
->sectp
->eolstring
=0;
550 while((lp
[0]!=0)||(p1
!=NULL
))
557 skip_space(scan
,&p1
);
559 skip_nonspace_quote(scan
,&p2
);
561 skip_space(scan
,&p3
);
563 skip_nonspace_quote(scan
,&p4
);
565 skip_space(scan
,&p5
);
567 skip_nonspace_quote(scan
,&p6
);
572 skip_space(scan
,&p3
);
574 skip_nonspace_quote(scan
,&p4
);
576 skip_space(scan
,&p5
);
578 skip_nonspace_quote(scan
,&p6
);
584 skip_space(scan
,&p5
);
586 skip_nonspace_quote(scan
,&p6
);
590 fprintf(stderr
,"doing line: line is [%s]\nlp=[%s]\np1=[%s]\np2=[%s]\np3=[%s]\np4=[%s]\np5=[%s]\np6=[%s]\n\n",
591 line
,lp
,p1
,p2
,p3
,p4
,p5
,p6
);
596 {p1}{p2}{p3}[ ]{p4}{p5}{p6} -> end of line
597 {p1}text{p2}[ ]{p3}{p4}{p5}{p6} -> word end of line
598 {p1}text=moretext{p2}... -> one word embedded assignment
599 {p1}text={p2}{p3}{p4}{p5}{p6} -> word assignment spills over line
600 {p1}={p2} .. -> continue assignment from prev line if possible
601 {p1}text={p2} {p3}text{p4} -> word assign 1
602 {p1}text{p2} {p3}=text{p4} -> word assign 2
603 {p1}text{p2} {p3}={p4} {p5}text{p6} -> word assign 3
604 {p1}text{p2} {p3}text={p4} -> word
605 text = EOL {p1}text{p2} .. -> eol continue
608 if(p1
==p2
){ p1
=NULL
; break; } /* end of line */
611 { if(p2
[-1]==def
->assignment
)arg
=1; }
613 if((arg
==0)&&(p2
>p1
))
616 if( (tmp
=memchr(p1
,def
->assignment
,p2
-p1
))!=NULL
)
622 skip_nonspace_quote(scan
,&p4
);
628 if(p3
[0]==def
->assignment
)
637 ncp
=make_card(scan
,p1
,p2
,NULL
,NULL
);
638 p1
=p3
; p2
=p4
; p3
=p5
; p4
=p6
; p5
=NULL
; lp
=p6
;
640 case 1: /* arg in p3 */
641 ncp
=make_card(scan
,p1
,p2
-1,p3
,p4
);
642 p1
=p5
; p2
=p6
; p3
=NULL
; p5
=NULL
; lp
=p6
;
644 case 2: /* arg in p3 or p4 */
647 ncp
=make_card(scan
,p1
,p2
,p3
+1,p4
);
648 p1
=p5
; p2
=p6
; p3
=NULL
; p5
=NULL
; lp
=p6
;
652 ncp
=make_card(scan
,p1
,p2
,p5
,p6
);
653 p1
=NULL
; p3
=NULL
; p5
=NULL
; lp
=p6
;
656 case 5: /* embedded arg, we've fixed up p's */
657 ncp
=make_card(scan
,p1
,p2
-1,p3
,p4
);
658 p1
=NULL
; p3
=NULL
; p5
=NULL
; lp
=p4
;
665 if(dbg
)fprintf(stderr
,"Adding card %s %i %s\n",ncp
->str
,ncp
->token
,ncp
->val
);
666 if(scan
->sectp
->dp
==NULL
)assert(0);
668 if(scan
->sectp
->dp
->card
==NULL
)
669 scan
->sectp
->dp
->card
=scan
->sectp
->cp
=ncp
;
672 if(scan
->sectp
->cp
!=NULL
)
674 scan
->sectp
->cp
->next
=ncp
;
675 scan
->sectp
->cp
=scan
->sectp
->cp
->next
;
682 if(dbg
)fprintf(stderr
,"card is null, line is [%s]\nlp=[%s]\np1=[%s]\np2=[%s]\np3=[%s]\np4=[%s]\np5=[%s]\np6=[%s]\n\n",
683 line
,lp
,p1
,p2
,p3
,p4
,p5
,p6
);
696 int scanner_parse_all(scanner_t
*scan
)
698 scan
->sectp
->eolstring
=0;
699 scan
->sectp
->line_cont
=0;
700 while(scanner_parse_line(scan
));
705 scanner_def_t
*scanner_def_spice(void)
707 static scanner_def_t spicedef
;
708 strcpy(spicedef
.line_stop
,".end_spice");
709 strcpy(spicedef
.eol_continue
,"\\");
710 strcpy(spicedef
.bol_continue
,"+");
711 spicedef
.convert_case
=PARSE_CASE_TOLOWER
;
712 spicedef
.quote_char
='\'';
713 spicedef
.newline
='\n';
714 spicedef
.assignment
='=';
715 strcpy(spicedef
.tokenize
,".");
716 strcpy(spicedef
.whitespace
," \t\n\r");
717 strcpy(spicedef
.commentstart
,"*");
721 char *scanner_token(scanner_t
*scan
, int token
)
723 return names_lookup(scan
->sectp
->tokenizer
,token
);
726 file_line_t
scanner_current_file_line(scanner_t
*scan
)
729 l
.fileindex
=scan
->inputp
->index
;
730 l
.line
=scan
->inputp
->line
;
734 void scanner_debug_all(scanner_t
*scan
, void *dbg
)
741 fprintf(fp
,"\n\n** begin \n\n");
742 for(d
=scan
->sectp
->dhead
;d
!=NULL
;d
=d
->next
)
745 fprintf(fp
,"\nline %i: ",d
->line
.line
);
746 for(c
=d
->card
;c
!=NULL
;c
=c
->next
)
749 fprintf(fp
," **%i=%s** ",c
->token
,scanner_token(scan
,c
->token
));
752 fprintf(fp
," [%s] ",c
->str
);
753 else fprintf(fp
," [%s]=[%s] ",c
->str
,c
->val
);
755 if(q
>=6){ fprintf(fp
,"\n "); q
=1; }
759 fprintf(fp
,"\n\n** .end\n\n");
762 /* parses 0101.0101.0101011.01 */
763 unsigned parse_binary(char **str
)
767 for(p
=*str
;p
[0]!=0;p
++)
773 { result
<<=1; result
|=1; }