testing
[gnucap-felix.git] / src / lang_spectre.cc
blobcf8c7b6994ab2979dec04eca33513dc6c1f5d93a
1 /*$Id: lang_spectre.cc 2015/01/27 al $ -*- C++ -*-
2 * Copyright (C) 2007 Albert Davis
3 * Author: Albert Davis <aldavis@gnu.org>
5 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
22 //testing=script 2015.01.27
23 #include "globals.h"
24 #include "c_comand.h"
25 #include "d_dot.h"
26 #include "d_coment.h"
27 #include "d_subckt.h"
28 #include "e_model.h"
29 #include "u_lang.h"
30 /*--------------------------------------------------------------------------*/
31 namespace {
32 /*--------------------------------------------------------------------------*/
33 class LANG_SPECTRE : public LANGUAGE {
34 public:
35 LANG_SPECTRE() {}
36 ~LANG_SPECTRE() {}
37 std::string name()const {return "spectre";}
38 bool case_insensitive()const {return false;}
39 UNITS units()const {return uSI;}
41 public: // override virtual, used by callback
42 std::string arg_front()const {unreachable();return " ";}
43 std::string arg_mid()const {unreachable();return "=";}
44 std::string arg_back()const {unreachable();return "";}
46 public: // override virtual, called by commands
47 void parse_top_item(CS&, CARD_LIST*);
48 DEV_COMMENT* parse_comment(CS&, DEV_COMMENT*);
49 DEV_DOT* parse_command(CS&, DEV_DOT*);
50 MODEL_CARD* parse_paramset(CS&, MODEL_CARD*);
51 BASE_SUBCKT* parse_module(CS&, BASE_SUBCKT*);
52 COMPONENT* parse_instance(CS&, COMPONENT*);
53 std::string find_type_in_string(CS&) const;
55 private: // override virtual, called by print_item
56 void print_paramset(OMSTREAM&, const MODEL_CARD*);
57 void print_module(OMSTREAM&, const BASE_SUBCKT*);
58 void print_instance(OMSTREAM&, const COMPONENT*);
59 void print_comment(OMSTREAM&, const DEV_COMMENT*);
60 void print_command(OMSTREAM& o, const DEV_DOT* c);
61 string getlines(FILE *fileptr) const;
62 private: // local
63 void print_args(OMSTREAM&, const CARD*);
64 static void parse_args(CS& cmd, CARD* x);
65 void parse_ports(CS& cmd, COMPONENT* x) const;
66 } lang_spectre;
68 DISPATCHER<LANGUAGE>::INSTALL
69 d(&language_dispatcher, lang_spectre.name(), &lang_spectre);
70 /*--------------------------------------------------------------------------*/
71 /*--------------------------------------------------------------------------*/
72 static void parse_type(CS& cmd, CARD* x)
74 assert(x);
75 std::string new_type;
76 cmd >> new_type;
77 x->set_dev_type(new_type);
79 /*--------------------------------------------------------------------------*/
80 void LANG_SPECTRE::parse_args(CS& cmd, CARD* x)
82 assert(x);
84 unsigned here = 0;
85 while (cmd.more() && !cmd.stuck(&here)) {
86 std::string name = cmd.ctos("=", "", "");
87 cmd >> '=';
88 std::string value = cmd.ctos("", "(", ")");
89 try{
90 trace2("parse_args", name, value);
91 x->set_param_by_name(name, value);
92 }catch (Exception_No_Match&) {
93 cmd.warn(bDANGER, here, x->long_label() + ": bad parameter " + name + " ignored");
97 /*--------------------------------------------------------------------------*/
98 static void parse_label(CS& cmd, CARD* x)
100 assert(x);
101 std::string my_name;
102 cmd >> my_name;
103 x->set_label(my_name);
105 /*--------------------------------------------------------------------------*/
106 void LANG_SPECTRE::parse_ports(CS& cmd, COMPONENT* x) const
108 assert(x);
110 uint_t index = 0;
111 if (cmd >> '(') {
112 while (cmd.is_alnum()) {
113 unsigned here = cmd.cursor();
114 try{
115 std::string value;
116 cmd >> value;
117 x->set_port_by_index(index++, value);
118 }catch (Exception_Too_Many& e) {
119 cmd.warn(bDANGER, here, e.message());
122 cmd >> ')';
123 }else{
124 unsigned here = cmd.cursor();
125 string s = find_type_in_string(cmd);
126 bool sub = (s=="subckt");
127 unsigned stop = cmd.cursor();
128 trace4("LANG_SPECTRE::parse_ports no paren", x->long_label(), s, cmd.tail(), stop);
129 cmd.reset(here);
130 trace1("LANG_SPECTRE::parse_ports here", cmd.tail());
132 while (cmd.cursor() < stop || ( sub && cmd.is_alnum())) {
133 here = cmd.cursor();
134 try{
135 std::string value;
136 cmd >> value;
137 x->set_port_by_index(index++, value);
138 }catch (Exception_Too_Many& e) {
139 cmd.warn(bDANGER, here, e.message());
143 if (index < x->min_nodes()) {
144 cmd.warn(bDANGER, "need " + to_string(x->min_nodes()-index) +" more nodes, grounding");
145 for (uint_t iii = index; iii < x->min_nodes(); ++iii) {
146 x->set_port_to_ground(iii);
148 }else{
151 /*--------------------------------------------------------------------------*/
152 /*--------------------------------------------------------------------------*/
153 DEV_COMMENT* LANG_SPECTRE::parse_comment(CS& cmd, DEV_COMMENT* x)
155 assert(x);
156 x->set(cmd.fullstring());
157 return x;
159 /*--------------------------------------------------------------------------*/
160 DEV_DOT* LANG_SPECTRE::parse_command(CS& cmd, DEV_DOT* x)
162 assert(x);
163 x->set(cmd.fullstring());
164 CARD_LIST* scope = (x->owner()) ? x->owner()->subckt() : &CARD_LIST::card_list;
166 cmd.reset().skipbl();
167 if ((cmd >> "model |simulator |parameters |subckt |list |eval |include ")) {
168 cmd.reset();
169 CMD::cmdproc(cmd, scope);
170 }else{
171 std::string label;
172 cmd >> label;
174 if (label != "-") {
175 unsigned here = cmd.cursor();
176 std::string command;
177 cmd >> command;
178 cmd.reset(here);
179 std::string file_name = label + '.' + command;
180 std::string s = cmd.tail() + " > " + file_name;
181 CS augmented_cmd(CS::_STRING, s);
182 CMD::cmdproc(augmented_cmd, scope);
183 }else{
184 CMD::cmdproc(cmd, scope);
187 delete x;
188 return NULL;
190 /*--------------------------------------------------------------------------*/
191 MODEL_CARD* LANG_SPECTRE::parse_paramset(CS& cmd, MODEL_CARD* x)
193 assert(x);
194 cmd.reset().skipbl();
195 cmd >> "model ";
196 parse_label(cmd, x);
197 parse_type(cmd, x);
198 parse_args(cmd, x);
199 cmd.check(bWARNING, "what's this?");
200 return x;
202 /*--------------------------------------------------------------------------*/
203 BASE_SUBCKT* LANG_SPECTRE::parse_module(CS& cmd, BASE_SUBCKT* x)
205 assert(x);
207 // header
208 cmd.reset().skipbl();
209 cmd >> "subckt ";
210 parse_label(cmd, x);
211 parse_ports(cmd, x);
213 // body
214 for (;;) {
215 cmd.get_line("spectre-subckt>");
217 if (cmd >> "ends ") {
218 break;
219 }else{
220 new__instance(cmd, x, x->subckt());
223 return x;
225 /*--------------------------------------------------------------------------*/
226 COMPONENT* LANG_SPECTRE::parse_instance(CS& cmd, COMPONENT* x)
228 assert(x);
229 cmd.reset();
230 parse_label(cmd, x);
231 parse_ports(cmd, x);
232 parse_type(cmd, x);
233 parse_args(cmd, x);
234 cmd.check(bWARNING, "what's this?");
235 return x;
237 /*--------------------------------------------------------------------------*/
238 std::string LANG_SPECTRE::find_type_in_string(CS& cmd) const
240 // known to be not always correct
242 cmd.reset().skipbl();
243 unsigned here = 0;
244 std::string type;
245 if ((cmd >> "*|//")) {
246 assert(here == 0);
247 type = "dev_comment";
248 }else if ((cmd >> "model |simulator |parameters |subckt |list |include |eval ")) {
249 // type is first, it's a control statement
250 type = cmd.trimmed_last_match();
251 }else if (cmd.reset().skiparg().match1("(") && cmd.scan(")")) {
252 // node list surrounded by parens
253 // type follows
254 here = cmd.cursor();
255 cmd.reset(here);
256 cmd >> type;
257 }else if (cmd.reset().scan("=")) {
258 // back up two, by starting over
259 cmd.reset().skiparg();
260 unsigned here1 = cmd.cursor();
261 cmd.skiparg();
262 unsigned here2 = cmd.cursor();
263 cmd.skiparg();
264 unsigned here3 = cmd.cursor();
265 while (here2 != here3 && !cmd.match1('=')) {
266 cmd.skiparg();
267 here1 = here2;
268 here2 = here3;
269 here3 = cmd.cursor();
271 here = here1;
272 cmd.reset(here);
273 cmd >> type;
274 }else{
275 // type is second
276 cmd.reset().skiparg();
277 here = cmd.cursor();
278 cmd.reset(here);
279 cmd >> type;
281 cmd.reset(here);
282 return type;
284 /*--------------------------------------------------------------------------*/
285 void LANG_SPECTRE::parse_top_item(CS& cmd, CARD_LIST* Scope)
287 cmd.get_line("gnucap-spectre>");
288 new__instance(cmd, NULL, Scope);
290 /*--------------------------------------------------------------------------*/
291 /*--------------------------------------------------------------------------*/
292 void LANG_SPECTRE::print_args(OMSTREAM& o, const CARD* x)
294 assert(x);
295 o << ' ';
296 if (x->use_obsolete_callback_print()) {
297 x->print_args_obsolete_callback(o, this); //BUG//callback//
298 }else{
299 for (int ii = x->param_count() - 1; ii >= 0; --ii) {
300 if (x->param_is_printable(ii)) {
301 std::string arg = " " + x->param_name(ii) + "=" + x->param_value(ii);
302 o << arg;
303 }else{
308 /*--------------------------------------------------------------------------*/
309 static void print_type(OMSTREAM& o, const COMPONENT* x)
311 assert(x);
312 o << ' ' << x->dev_type();
314 /*--------------------------------------------------------------------------*/
315 static void print_label(OMSTREAM& o, const COMPONENT* x)
317 assert(x);
318 o << x->short_label();
320 /*--------------------------------------------------------------------------*/
321 static void print_ports(OMSTREAM& o, const COMPONENT* x)
323 assert(x);
325 o << " (";
326 std::string sep = "";
327 for (uint_t ii = 0; x->port_exists(ii); ++ii) {
328 o << sep << x->port_value(ii);
329 sep = " ";
331 for (uint_t ii = 0; x->current_port_exists(ii); ++ii) {untested();
332 o << sep << x->current_port_value(ii);
333 sep = " ";
335 o << ")";
337 /*--------------------------------------------------------------------------*/
338 /*--------------------------------------------------------------------------*/
339 void LANG_SPECTRE::print_paramset(OMSTREAM& o, const MODEL_CARD* x)
341 assert(x);
342 o << "model " << x->short_label() << ' ' << x->dev_type() << ' ';
343 print_args(o, x);
344 o << "\n\n";
346 /*--------------------------------------------------------------------------*/
347 void LANG_SPECTRE::print_module(OMSTREAM& o, const BASE_SUBCKT* x)
349 assert(x);
350 assert(x->subckt());
352 o << "subckt " << x->short_label();
353 print_ports(o, x);
354 o << "\n";
356 for (CARD_LIST::const_iterator
357 ci = x->subckt()->begin(); ci != x->subckt()->end(); ++ci) {
358 print_item(o, *ci);
361 o << "ends " << x->short_label() << "\n\n";
363 /*--------------------------------------------------------------------------*/
364 void LANG_SPECTRE::print_instance(OMSTREAM& o, const COMPONENT* x)
366 print_label(o, x);
367 print_ports(o, x);
368 print_type(o, x);
369 print_args(o, x);
370 o << "\n";
372 /*--------------------------------------------------------------------------*/
373 void LANG_SPECTRE::print_comment(OMSTREAM& o, const DEV_COMMENT* x)
375 assert(x);
376 if (x->comment()[0] != '*') {
377 o << "*";
378 }else{untested();
380 o << x->comment() << '\n';
382 /*--------------------------------------------------------------------------*/
383 void LANG_SPECTRE::print_command(OMSTREAM& o, const DEV_DOT* x)
384 {untested();
385 assert(x);
386 o << x->s() << '\n';
388 /*--------------------------------------------------------------------------*/
389 std::string LANG_SPECTRE::getlines(FILE *fileptr) const
391 assert(fileptr);
392 const int buffer_size = BIGBUFLEN;
393 std::string s;
395 bool need_to_get_more = true; // get another line (extend)
396 while (need_to_get_more) {
397 char buffer[buffer_size+1];
398 char* got_something = fgets(buffer, buffer_size, fileptr);
399 if (!got_something) { // probably end of file
400 need_to_get_more = false;
401 if (s == "") {
402 throw Exception_End_Of_Input("");
403 }else{untested();
405 }else{
406 trim(buffer);
407 size_t count = strlen(buffer);
408 if(count==0){
409 }else if (buffer[count-1] == '\\') {itested();
410 buffer[count-1] = '\0';
411 }else{
412 // look ahead at next line
413 //int c = fgetc(fileptr);
415 int c;
416 while (isspace(c = fgetc(fileptr)));
417 assert(c!='\n');
418 if (c == '+') {
419 need_to_get_more = true;
420 }else{
421 need_to_get_more = false;
422 ungetc(c,fileptr);
425 s += buffer;
426 s += ' ';
429 return s;
431 /*--------------------------------------------------------------------------*/
432 /*--------------------------------------------------------------------------*/
433 class CMD_MODEL : public CMD {
434 void do_it(CS& cmd, CARD_LIST* Scope)
436 // already got "model"
437 std::string my_name, base_name;
438 cmd >> my_name;
439 unsigned here = cmd.cursor();
440 cmd >> base_name;
442 //const MODEL_CARD* p = model_dispatcher[base_name];
443 const CARD* p = lang_spectre.find_proto(base_name, NULL);
444 if (p) {
445 MODEL_CARD* new_card = dynamic_cast<MODEL_CARD*>(p->clone());
446 if (new_card) {
447 assert(!new_card->owner());
448 lang_spectre.parse_paramset(cmd, new_card);
449 Scope->push_back(new_card);
450 }else{untested();
451 cmd.warn(bDANGER, here, "model: base has incorrect type");
453 }else{untested();
454 cmd.warn(bDANGER, here, "model: no match");
457 } p1;
458 DISPATCHER<CMD>::INSTALL d1(&command_dispatcher, "model", &p1);
459 /*--------------------------------------------------------------------------*/
460 class CMD_SUBCKT : public CMD {
461 void do_it(CS& cmd, CARD_LIST* Scope)
463 const CARD* s = device_dispatcher["subckt"];
464 assert(s); // for now
465 BASE_SUBCKT* new_module = dynamic_cast<BASE_SUBCKT*>(s->clone());
466 assert(new_module);
467 assert(!new_module->owner());
468 assert(new_module->subckt());
469 assert(new_module->subckt()->is_empty());
470 lang_spectre.parse_module(cmd, new_module);
471 Scope->push_back(new_module);
473 } p2;
474 DISPATCHER<CMD>::INSTALL d2(&command_dispatcher, "subckt", &p2);
475 /*--------------------------------------------------------------------------*/
476 class CMD_SIMULATOR : public CMD {
477 void do_it(CS& cmd, CARD_LIST* Scope)
479 command("options " + cmd.tail(), Scope);
481 } p3;
482 DISPATCHER<CMD>::INSTALL d3(&command_dispatcher, "simulator", &p3);
483 /*--------------------------------------------------------------------------*/
484 class CMD_SPECTRE : public CMD {
485 public:
486 void do_it(CS&, CARD_LIST* Scope)
488 command("options lang=spectre", Scope);
490 } p8;
491 DISPATCHER<CMD>::INSTALL d8(&command_dispatcher, "spectre", &p8);
492 /*--------------------------------------------------------------------------*/
494 /*--------------------------------------------------------------------------*/
495 /*--------------------------------------------------------------------------*/
496 // vim:ts=8:sw=2:noet: