nec2++ 2.1.1
nec_card_parser.h
1#pragma once
2
3/*
4 Clean NEC card parser — replaces the FORTRAN-style readmn() with
5 std::string-based parsing and table-driven dispatch.
6
7 Copyright (C) 2025 Timothy C.A. Molteno
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
15#include <string>
16#include <vector>
17#include <sstream>
18#include <cstring>
19#include <cstdlib>
20
21#include "common.h"
22
23/*-----------------------------------------------------------------------*/
24/* Parsed NEC card */
25
26struct nec_card {
27 std::string mnemonic;
28 int i[4] = {0,0,0,0};
29 double f[7] = {0.,0.,0.,0.,0.,0.,0.};
30 int parameter_count = 0;
31
32 bool is(const char* m) const { return mnemonic == m; }
33};
34
35/*-----------------------------------------------------------------------*/
36/* Parse a single NEC card line into a nec_card struct. */
37/* Handles: comma or space separators, negative numbers, E-notation, */
38/* inline ' comments, leading # comment lines. */
39
40inline nec_card parse_nec_card(const std::string& line) {
41 nec_card card;
42 if (line.size() < 2)
43 return card;
44
45 /* Check for # comment lines */
46 if (line[0] == '#')
47 return card;
48
49 /* Extract mnemonic */
50 card.mnemonic = line.substr(0, 2);
51
52 /* Find the ' comment delimiter and truncate */
53 std::string rest = line.substr(2);
54 size_t comment_pos = rest.find('\'');
55 if (comment_pos != std::string::npos)
56 rest = rest.substr(0, comment_pos);
57
58 /* Parse remaining fields: replace commas with spaces for uniform parsing */
59 for (auto& ch : rest)
60 if (ch == ',') ch = ' ';
61
62 std::stringstream ss(rest);
63 std::string token;
64
65 /* First 4 fields are integers */
66 for (int n = 0; n < 4; n++) {
67 if (!(ss >> token)) break;
68 card.i[n] = std::atoi(token.c_str());
69 card.parameter_count++;
70 }
71
72 /* Next 6 fields are floats */
73 for (int n = 0; n < 6; n++) {
74 if (!(ss >> token)) break;
75 card.f[n] = std::atof(token.c_str());
76 card.parameter_count++;
77 }
78
79 return card;
80}
81
82/*-----------------------------------------------------------------------*/
83/* Table-driven card dispatch (replaces atst[] + giant switch) */
84
85class nec_context; // forward decl
86
88 const char* name;
89 void (*dispatch)(nec_context& ctx, const nec_card& card);
90};
91
92/* Dispatch helpers — one per card type */
93void handle_fr(nec_context& ctx, const nec_card& c);
94void handle_ld(nec_context& ctx, const nec_card& c);
95void handle_gn(nec_context& ctx, const nec_card& c);
96void handle_ex(nec_context& ctx, const nec_card& c);
97void handle_nt(nec_context& ctx, const nec_card& c);
98void handle_tl(nec_context& ctx, const nec_card& c);
99void handle_xq(nec_context& ctx, const nec_card& c);
100void handle_gd(nec_context& ctx, const nec_card& c);
101void handle_rp(nec_context& ctx, const nec_card& c);
102void handle_nx(nec_context& ctx, const nec_card& c);
103void handle_pt(nec_context& ctx, const nec_card& c);
104void handle_kh(nec_context& ctx, const nec_card& c);
105void handle_ne(nec_context& ctx, const nec_card& c);
106void handle_nh(nec_context& ctx, const nec_card& c);
107void handle_pq(nec_context& ctx, const nec_card& c);
108void handle_ek(nec_context& ctx, const nec_card& c);
109void handle_cp(nec_context& ctx, const nec_card& c);
110void handle_pl(nec_context& ctx, const nec_card& c);
111void handle_en(nec_context& ctx, const nec_card& c);
112void handle_wg(nec_context& ctx, const nec_card& c);
113void handle_mp(nec_context& ctx, const nec_card& c);
114
115/* The handler table — all 21 NEC card types in one place */
116static const card_handler card_handlers[] = {
117 {"FR", handle_fr}, {"LD", handle_ld}, {"GN", handle_gn},
118 {"EX", handle_ex}, {"NT", handle_nt}, {"TL", handle_tl},
119 {"XQ", handle_xq}, {"GD", handle_gd}, {"RP", handle_rp},
120 {"NX", handle_nx}, {"PT", handle_pt}, {"KH", handle_kh},
121 {"NE", handle_ne}, {"NH", handle_nh}, {"PQ", handle_pq},
122 {"EK", handle_ek}, {"CP", handle_cp}, {"PL", handle_pl},
123 {"EN", handle_en}, {"WG", handle_wg}, {"MP", handle_mp},
124};
125
126inline const card_handler* find_handler(const std::string& mnemonic) {
127 for (const auto& h : card_handlers)
128 if (h.name[0] == mnemonic[0] && h.name[1] == mnemonic[1])
129 return &h;
130 return nullptr;
131}
Container for an nec2++ simulation.
Definition nec_context.h:80
Definition nec_card_parser.h:87
Definition nec_card_parser.h:26