xschem/src/parselabel.l

304 lines
11 KiB
Plaintext

/* File: parselabel.l
*
* This file is part of XSCHEM,
* a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
* simulation.
* Copyright (C) 1998-2021 Stefan Frederik Schippers
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
%option never-interactive
%option noyywrap
%option noinput
%option nounput
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAD_SPICE_NETLIST 1
int dbg_var = 0;
#include "xschem.h"
/*
extern int xctx;
extern int has_x;
extern FILE *errfp;
extern size_t my_strdup(int id, char **dest, const char *src);
extern void my_free(int id, void *ptr);
extern char bus_char[];
extern const char *tcleval(const char str[]);
extern void *my_malloc(int id, size_t size);
extern int my_snprintf(char *str, int size, const char *fmt, ...);
*/
#ifndef STRINGPTR
#define STRINGPTR
typedef struct /* used in expandlabel.y */
{
char *str; /* label name */
int m; /* label multiplicity, number of wires */
} Stringptr;
#endif
/* commented 20170412, fixes problems with older bison/flex versions */
/* #define YYPARSE_PARAM */
#include "expandlabel.h" /* Bison header file */
Stringptr dest_string={NULL,0}; /*19102004; */
extern int yyparse(void) ;
extern int yyparse_error;
extern int yylex();
void clear_expandlabel_data(void)
{
my_free(868, &dest_string.str);
}
void str_char_replace(char s[], char chr, char repl_chr)
{
int i=0;
while(s[i]!='\0')
{
if(s[i]==chr)
{
s[i]=repl_chr;
}
i++;
}
}
void parse(const char *s)
{
YY_BUFFER_STATE buf;
buf=yy_scan_string(s);
while(yylex()){
fprintf(errfp, "token:|%s|\n", yytext);
}
yy_delete_buffer(buf);
}
const char *expandlabel(const char *s, int *m)
{
YY_BUFFER_STATE buf;
my_free(869, &dest_string.str); /* 30102004 delete 'memory' of previous execution */
if(dbg_var >= 3) fprintf(errfp, "expandlabel(): entering\n");
buf=yy_scan_string(s);
yyparse();
yy_delete_buffer(buf);
if(yyparse_error==1) {
char *cmd = NULL;
int l;
yyparse_error = -1;
l = strlen(s)+120;
cmd = my_malloc(526, l);
fprintf(errfp, "syntax error in %s\n", s);
my_snprintf(cmd, l,
"tk_messageBox -icon error -type ok -parent [xschem get topwindow] "
"-message {Syntax error in identifier expansion: %s}", s);
if(has_x) tcleval(cmd);
my_free(543, &cmd);
}
if(dbg_var >= 3)
fprintf(errfp, "expandlabel(): returning %s from %s mult=%d\n",dest_string.str, s, dest_string.m);
if(dest_string.str)
*m = dest_string.m;
else
*m=-1;
if(dest_string.str) {
if(xctx->netlist_type == CAD_SPICE_NETLIST && bus_char[0] && bus_char[1]) {
str_char_replace(dest_string.str, '[', bus_char[0]);
str_char_replace(dest_string.str, ']', bus_char[1]);
}
return dest_string.str;
} else {
return s;
}
}
%}
/*
Lexical analyzer
*/
%x index
%x mult
SP [ \t\n]*
NOTSP [^ \t\n]
INT [0-9]+
DDOT {SP}".."{SP}
CLN {SP}":"{SP}
LAB [-a-zA-Z_%$~"+#!/\\<>]
/* includes numbers */
LAB_NUM [-a-zA-Z_%$~"+#!/\\<>0-9]
/* includes numbers and space and *+(). */
IDX_LAB_NUM_SP [-a-zA-Z_%$~"#!/\\<> \t\n0-9*+().]
/* identifier, may start with a number */
IDX_ID_N ({LAB_NUM}+({IDX_LAB_NUM_SP}*{LAB_NUM})*)
/* identifier, not starting with a number */
IDX_ID (("("|{LAB})+{IDX_LAB_NUM_SP}*)
/* includes numbers and space and +(). and :*/
LAB_NUM_SP [-a-zA-Z_%$~"#!:/\\<> \t\n0-9+().]
/* identifier, may start with a number */
ID_NUM ({LAB_NUM}+({LAB_NUM_SP}*{LAB_NUM})*\??)
/* identifier, not starting with a number */
ID (("("|{LAB})+{LAB_NUM_SP}*\??)
/* ~#diUV=9_(\#-hgvUY=) */
ID_EXT_PARENTHESIS ([-~"#+/=_a-zA-Z][-#!@\\/:.=_+a-zA-Z0-9]*\([-~"#!@\\/:.=_+a-zA-Z0-9]*\))
%%
/* this action resets initial condition at start of line. This is extremely useful if previously lexer
* bailed out in the middle of some non INITIAL start condition due to yyparse() syntax errors */
<mult,index>^. {
if(dbg_var >= 3) fprintf(errfp, "yylex(): matched: ^[^*] |%s|, push back\n",yytext);
yyless(0); /* push entire token back to input */
BEGIN(INITIAL); /* reset parser */
}
<mult>{
/* postfix multiplier */
{INT} {
sscanf(yytext, "%d",&yylval.val);
if(dbg_var >= 3) fprintf(errfp, "yylex(): postmult B_NUM: |%s|\n", yytext);
BEGIN(INITIAL);
return B_NUM;
}
} /* end <mult> */
/* node indexes: "3:2" "5:1:2" "5..1" "7..1..2" "b:a" "c:b:a" .... */
<index>{
{INT} {
sscanf(yytext, "%d",&yylval.val);
if(dbg_var >= 3) fprintf(errfp, "yylex(): B_IDXNUM: |%s|\n", yytext);
return B_IDXNUM;
}
{DDOT} {
if(dbg_var >= 3) fprintf(errfp, "yylex(): B_DOUBLEDOT: |%s|\n", yytext);
return B_DOUBLEDOT;
}
/* end vector node index "...]" */
\] {
if(dbg_var >= 3) fprintf(errfp, "yylex(): close bracket: %s\n", yytext);
BEGIN(INITIAL);
return yytext[0];
}
{NOTSP} {
if(dbg_var >= 3) fprintf(errfp, "yylex(): idx character: |%s|\n", yytext);
return yytext[0];
}
/* recognize AA[aa:bb:33] or AA[33:cc:dd] or AA[aa..bb..11] .... */
({IDX_ID}{DDOT}{IDX_ID_N}{DDOT}{IDX_ID_N})|({IDX_ID_N}{DDOT}{IDX_ID}{DDOT}{IDX_ID_N})|({IDX_ID_N}{DDOT}{IDX_ID_N}{DDOT}{IDX_ID}) {
yylval.ptr.str=NULL;
my_strdup(428, &yylval.ptr.str, yytext);
if(dbg_var >= 3) fprintf(errfp, "yylex(): B_NAME3: |%s|\n", yytext);
return B_NAME;
}
({IDX_ID}{CLN}{IDX_ID_N}{CLN}{IDX_ID_N})|({IDX_ID_N}{CLN}{IDX_ID}{CLN}{IDX_ID_N})|({IDX_ID_N}{CLN}{IDX_ID_N}{CLN}{IDX_ID}) {
yylval.ptr.str=NULL;
my_strdup(430, &yylval.ptr.str, yytext);
if(dbg_var >= 3) fprintf(errfp, "yylex(): B_NAME2: |%s|\n", yytext);
return B_NAME;
}
/* recognize AA[width-1:0], AA[0:width-1], AA[width-1..4], AA[3..width+3], AA[aa:bb] AA[aa..bb] */
({IDX_ID}{CLN}{IDX_ID_N})|({IDX_ID_N}{CLN}{IDX_ID})|({IDX_ID}{DDOT}{IDX_ID_N})|({IDX_ID_N}{DDOT}{IDX_ID}) {
yylval.ptr.str=NULL;
my_strdup(92, &yylval.ptr.str, yytext);
if(dbg_var >= 3) fprintf(errfp, "yylex(): B_NAME1: |%s|\n", yytext);
return B_NAME;
}
} /* end <index> */
/* a comment, return as LINE token */
^\*.* {
yylval.ptr.str=NULL; /*19102004 */
if(dbg_var >= 3) fprintf(errfp, "yylex(): B_LINE: |%s|\n",yytext);
my_strdup(299, &yylval.ptr.str, yytext); /* freed after use in expandlabel.y */
BEGIN(INITIAL);
return B_LINE;
}
/* prefix multiplier */
{INT}/{SP}\*{SP} {
sscanf(yytext, "%d",&yylval.val);
if(dbg_var >= 3) fprintf(errfp, "yylex(): premult B_NUM: |%s|\n", yytext);
BEGIN(INITIAL);
return B_NUM;
}
/* a number: if not a multiplier nor a node index return as a node name */
{INT} {
yylval.ptr.str=NULL;
my_strdup(120, &yylval.ptr.str, yytext);
if(dbg_var >= 3) fprintf(errfp, "yylex(): B_NAME4: |%s|\n", yytext);
BEGIN(INITIAL);
return B_NAME;
}
{SP} {
if(dbg_var >= 3) fprintf(errfp, "yylex(): skipping: |%s|\n", yytext);
}
/* comma separator between nodes: chop spaces "a,b , c" */
{SP},{SP} {
yylval.val=',';
if(dbg_var >= 3) fprintf(errfp, "yylex(): comma: |%s|\n", yytext);
BEGIN(INITIAL);
return ',';
}
/* recognize the most esotheric identifiers */
{ID_NUM}|{ID_EXT_PARENTHESIS} {
yylval.ptr.str=NULL;/*19102004 */
my_strdup(300, &yylval.ptr.str, yytext); /* freed after use in expandlabel.y */
if(dbg_var >= 3) fprintf(errfp, "yylex(): B_NAME0: |%s|\n", yytext);
BEGIN(INITIAL);
return B_NAME;
}
/* start vector node index: "aa[" */
\[ {
if(dbg_var >= 3) fprintf(errfp, "yylex(): open bracket: %s\n", yytext);
BEGIN(index);
return yytext[0];
}
/* "*(aa,bb,cc)" or "*aaa" prefix multiplication*/
{SP}\*{SP}/({ID}|[(]) {
if(dbg_var >= 3) fprintf(errfp, "yylex(): pre *: |%s|\n", yytext);
BEGIN(INITIAL);
return '*';
}
/* "*16" postfix multiplication */
{SP}\*{SP}/{INT} {
if(dbg_var >= 3) fprintf(errfp, "yylex(): post *: |%s|\n", yytext);
BEGIN(mult);
return '*';
}
{NOTSP} {
if(dbg_var >= 3) fprintf(errfp, "yylex(): character: |%s|\n", yytext);
BEGIN(INITIAL);
return yytext[0];
}
<*><<EOF>> {
BEGIN(INITIAL);
return 0;
}
%%