Ostatnio aktywny 1 month ago

's Avatar zdebel zrewidował ten Gist 1 month ago. Przejdź do rewizji

1 file changed, 405 insertions

basic.c(stworzono plik)

@@ -0,0 +1,405 @@
1 + #include <stdio.h>
2 + #include <stdlib.h>
3 + #include <string.h>
4 + #include <ctype.h>
5 + #include <math.h>
6 + #include <time.h>
7 +
8 + /* ---- constants ---- */
9 + #define MAXLINES 1000
10 + #define MAXBUF 256
11 + #define MAXVARS 256
12 + #define MAXSTACK 256
13 + #define MAXDATA 1024
14 +
15 + /* ---- program storage ---- */
16 + typedef struct { int num; char text[MAXBUF]; } Line;
17 + Line program[MAXLINES];
18 + int prog_cnt = 0;
19 +
20 + /* ---- variables (numeric only for now) ---- */
21 + char var_names[MAXVARS][3];
22 + double var_vals[MAXVARS];
23 + int var_cnt = 0;
24 +
25 + /* ---- DATA pool ---- */
26 + double data_pool[MAXDATA];
27 + int data_count = 0;
28 + int data_pos = 0;
29 +
30 + /* ---- GOSUB stack (BAKSTK) ---- */
31 + int call_stack[MAXSTACK];
32 + int call_sp = 0;
33 +
34 + /* ---- FOR/NEXT stack ---- */
35 + typedef struct { int var_idx; double limit; double step; int line_idx; } ForEntry;
36 + ForEntry for_stack[MAXSTACK];
37 + int for_sp = 0;
38 +
39 + /* ---- globals ---- */
40 + double fac;
41 + int cur_line_idx; /* index into program[] */
42 + int running;
43 +
44 + /* ============================================================
45 + FIND_LINE - like SRCHLN
46 + ============================================================ */
47 + int find_line(int num) {
48 + for (int i = 0; i < prog_cnt; i++)
49 + if (program[i].num == num) return i;
50 + return -1;
51 + }
52 +
53 + /* ============================================================
54 + PTRGET - find or create variable
55 + ============================================================ */
56 + int ptrget(const char *name) {
57 + char n[3] = {0};
58 + n[0] = toupper(name[0]);
59 + if (isalnum(name[1])) n[1] = toupper(name[1]);
60 + for (int i = 0; i < var_cnt; i++)
61 + if (strcmp(n, var_names[i]) == 0) return i;
62 + strcpy(var_names[var_cnt], n);
63 + var_vals[var_cnt] = 0.0;
64 + return var_cnt++;
65 + }
66 +
67 + /* ============================================================
68 + EXPRESSION PARSER (EVAL / OPRND)
69 + Supports: numbers, variables, +,-,*,/,^,(),ABS,SQR,RND,INT
70 + ============================================================ */
71 + double expr(char **p);
72 +
73 + static void skip_ws(char **p) { while (**p == ' ') (*p)++; }
74 +
75 + static double primary(char **p) {
76 + skip_ws(p);
77 + double x = 0;
78 + /* Unary minus */
79 + if (**p == '-') { (*p)++; return -primary(p); }
80 + /* Parenthesis */
81 + if (**p == '(') {
82 + (*p)++;
83 + x = expr(p);
84 + skip_ws(p);
85 + if (**p == ')') (*p)++;
86 + return x;
87 + }
88 + /* String check: ABS, SQR, RND, INT */
89 + if (strncasecmp(*p, "ABS(", 4) == 0) { *p+=4; x=fabs(expr(p)); skip_ws(p); if(**p==')')(*p)++; return x; }
90 + if (strncasecmp(*p, "SQR(", 4) == 0) { *p+=4; x=sqrt(expr(p)); skip_ws(p); if(**p==')')(*p)++; return x; }
91 + if (strncasecmp(*p, "INT(", 4) == 0) { *p+=4; x=floor(expr(p)); skip_ws(p); if(**p==')')(*p)++; return x; }
92 + if (strncasecmp(*p, "RND(", 4) == 0) { *p+=4; expr(p); skip_ws(p); if(**p==')')(*p)++; return (double)rand()/RAND_MAX; }
93 + if (strncasecmp(*p, "SIN(", 4) == 0) { *p+=4; x=sin(expr(p)); skip_ws(p); if(**p==')')(*p)++; return x; }
94 + if (strncasecmp(*p, "COS(", 4) == 0) { *p+=4; x=cos(expr(p)); skip_ws(p); if(**p==')')(*p)++; return x; }
95 + if (strncasecmp(*p, "LOG(", 4) == 0) { *p+=4; x=log(expr(p)); skip_ws(p); if(**p==')')(*p)++; return x; }
96 + if (strncasecmp(*p, "EXP(", 4) == 0) { *p+=4; x=exp(expr(p)); skip_ws(p); if(**p==')')(*p)++; return x; }
97 + /* Number literal */
98 + if (isdigit(**p) || **p == '.') {
99 + char *end; x = strtod(*p, &end); *p = end; return x;
100 + }
101 + /* Variable */
102 + if (isalpha(**p)) {
103 + char name[3] = {0};
104 + name[0] = toupper(*(*p)++);
105 + if (isalnum(**p)) name[1] = toupper(*(*p)++);
106 + return var_vals[ptrget(name)];
107 + }
108 + return 0;
109 + }
110 +
111 + static double power(char **p) {
112 + double x = primary(p);
113 + skip_ws(p);
114 + if (**p == '^') { (*p)++; x = pow(x, primary(p)); }
115 + return x;
116 + }
117 +
118 + static double term(char **p) {
119 + double x = power(p);
120 + skip_ws(p);
121 + while (**p == '*' || **p == '/') {
122 + char op = *(*p)++;
123 + double y = power(p);
124 + x = (op == '*') ? x*y : x/y;
125 + skip_ws(p);
126 + }
127 + return x;
128 + }
129 +
130 + double expr(char **p) {
131 + double x = term(p);
132 + skip_ws(p);
133 + while (**p == '+' || **p == '-') {
134 + char op = *(*p)++;
135 + double y = term(p);
136 + x = (op == '+') ? x+y : x-y;
137 + skip_ws(p);
138 + }
139 + return fac = x;
140 + }
141 +
142 + /* Relational: returns 1/0 */
143 + double rel_expr(char **p) {
144 + double x = expr(p);
145 + skip_ws(p);
146 + if (strncmp(*p,"<>",2)==0) { *p+=2; return x != expr(p); }
147 + if (strncmp(*p,"<=",2)==0) { *p+=2; return x <= expr(p); }
148 + if (strncmp(*p,">=",2)==0) { *p+=2; return x >= expr(p); }
149 + if (**p=='<') { (*p)++; return x < expr(p); }
150 + if (**p=='>') { (*p)++; return x > expr(p); }
151 + if (**p=='=') { (*p)++; return x == expr(p); }
152 + return x;
153 + }
154 +
155 + /* ============================================================
156 + COLLECT DATA (FDTLP)
157 + ============================================================ */
158 + void collect_data() {
159 + data_count = 0; data_pos = 0;
160 + for (int i = 0; i < prog_cnt; i++) {
161 + char *p = program[i].text;
162 + while (*p && strncasecmp(p,"DATA",4)!=0) p++;
163 + if (!*p) continue;
164 + p += 4;
165 + while (*p) {
166 + skip_ws(&p);
167 + if (*p == ',') p++;
168 + skip_ws(&p);
169 + if (!*p) break;
170 + char *end; double v = strtod(p,&end);
171 + if (end != p) { data_pool[data_count++] = v; p = end; }
172 + else break;
173 + }
174 + }
175 + }
176 +
177 + /* ============================================================
178 + INSERT LINE (PROMPT / TOKENIZE)
179 + ============================================================ */
180 + void insert_line(int num, char *text) {
181 + /* Replace existing */
182 + for (int i = 0; i < prog_cnt; i++) {
183 + if (program[i].num == num) {
184 + if (!text || !*text) {
185 + /* Delete */
186 + for (int j = i; j < prog_cnt-1; j++) program[j]=program[j+1];
187 + prog_cnt--; return;
188 + }
189 + strncpy(program[i].text, text, MAXBUF-1);
190 + return;
191 + }
192 + }
193 + if (!text || !*text) return;
194 + /* Insert sorted */
195 + program[prog_cnt].num = num;
196 + strncpy(program[prog_cnt].text, text, MAXBUF-1);
197 + prog_cnt++;
198 + /* Bubble sort by line number */
199 + for (int i = prog_cnt-1; i > 0 && program[i].num < program[i-1].num; i--) {
200 + Line tmp = program[i]; program[i] = program[i-1]; program[i-1] = tmp;
201 + }
202 + }
203 +
204 + /* ============================================================
205 + EXECUTE ONE LINE (NEWSTT / EXEC / FNCTAB)
206 + ============================================================ */
207 + void execute_line(char *stmt);
208 + void run_from(int idx);
209 +
210 + void execute_stmt(char *p) {
211 + skip_ws(&p);
212 + /* REM / ' */
213 + if (strncasecmp(p,"REM",3)==0 || *p=='\'') return;
214 + /* PRINT */
215 + if (strncasecmp(p,"PRINT",5)==0) {
216 + p += 5;
217 + while (*p) {
218 + skip_ws(&p);
219 + if (!*p) break;
220 + if (*p == '"') {
221 + p++;
222 + while (*p && *p!='"') putchar(*p++);
223 + if (*p=='"') p++;
224 + } else if (*p==';') { p++; continue; }
225 + else if (*p==',') { printf("\t"); p++; continue; }
226 + else { printf("%g", rel_expr(&p)); }
227 + skip_ws(&p);
228 + }
229 + printf("\n");
230 + return;
231 + }
232 + /* INPUT */
233 + if (strncasecmp(p,"INPUT",5)==0) {
234 + p += 5; skip_ws(&p);
235 + if (*p=='"') { p++; while(*p && *p!='"') putchar(*p++); if(*p=='"')p++; if(*p==',')p++; printf("? "); }
236 + else printf("? ");
237 + char name[3]={0}; name[0]=toupper(*p++); if(isalnum(*p)) name[1]=toupper(*p++);
238 + double v; scanf("%lf",&v); getchar();
239 + var_vals[ptrget(name)] = v;
240 + return;
241 + }
242 + /* LET or assignment */
243 + if (strncasecmp(p,"LET",3)==0) p+=3;
244 + /* Detect assignment: name = */
245 + if (isalpha(*p)) {
246 + char name[3]={0}; char *save=p;
247 + name[0]=toupper(*p++); if(isalnum(*p)) name[1]=toupper(*p++);
248 + skip_ws(&p);
249 + if (*p=='=') {
250 + p++; var_vals[ptrget(name)] = expr(&p); return;
251 + }
252 + p = save;
253 + }
254 + /* IF */
255 + if (strncasecmp(p,"IF",2)==0) {
256 + p+=2; skip_ws(&p);
257 + double cond = rel_expr(&p);
258 + skip_ws(&p);
259 + if (strncasecmp(p,"THEN",4)==0) p+=4;
260 + skip_ws(&p);
261 + if (cond) execute_stmt(p);
262 + return;
263 + }
264 + /* GOTO */
265 + if (strncasecmp(p,"GOTO",4)==0) {
266 + p+=4; int tgt=(int)expr(&p);
267 + int idx=find_line(tgt);
268 + if (idx<0) { printf("?Undefined line %d\n",tgt); running=0; return; }
269 + cur_line_idx = idx; running = 2; return;
270 + }
271 + /* GOSUB */
272 + if (strncasecmp(p,"GOSUB",5)==0) {
273 + p+=5; int tgt=(int)expr(&p);
274 + int idx=find_line(tgt);
275 + if (idx<0) { printf("?Undefined line %d\n",tgt); running=0; return; }
276 + call_stack[call_sp++] = cur_line_idx+1;
277 + cur_line_idx = idx; running = 2; return;
278 + }
279 + /* RETURN */
280 + if (strncasecmp(p,"RETURN",6)==0) {
281 + if (call_sp<=0) { printf("?RETURN without GOSUB\n"); running=0; return; }
282 + cur_line_idx = call_stack[--call_sp]; running = 2; return;
283 + }
284 + /* FOR */
285 + if (strncasecmp(p,"FOR",3)==0) {
286 + p+=3; skip_ws(&p);
287 + char name[3]={0}; name[0]=toupper(*p++); if(isalnum(*p)) name[1]=toupper(*p++);
288 + skip_ws(&p); if(*p=='=') p++;
289 + double start=expr(&p);
290 + skip_ws(&p); if(strncasecmp(p,"TO",2)==0) p+=2;
291 + double limit=expr(&p);
292 + double step=1.0;
293 + skip_ws(&p); if(strncasecmp(p,"STEP",4)==0) { p+=4; step=expr(&p); }
294 + int vi=ptrget(name); var_vals[vi]=start;
295 + for_stack[for_sp].var_idx=vi;
296 + for_stack[for_sp].limit=limit;
297 + for_stack[for_sp].step=step;
298 + for_stack[for_sp].line_idx=cur_line_idx;
299 + for_sp++;
300 + return;
301 + }
302 + /* NEXT */
303 + if (strncasecmp(p,"NEXT",4)==0) {
304 + if (for_sp<=0) { printf("?NEXT without FOR\n"); running=0; return; }
305 + ForEntry *fe = &for_stack[for_sp-1];
306 + var_vals[fe->var_idx] += fe->step;
307 + if ((fe->step>0 && var_vals[fe->var_idx] <= fe->limit) ||
308 + (fe->step<0 && var_vals[fe->var_idx] >= fe->limit)) {
309 + cur_line_idx = fe->line_idx; running=2;
310 + } else { for_sp--; }
311 + return;
312 + }
313 + /* READ */
314 + if (strncasecmp(p,"READ",4)==0) {
315 + p+=4; skip_ws(&p);
316 + while(*p) {
317 + skip_ws(&p);
318 + if(*p==',') p++;
319 + skip_ws(&p);
320 + if(!*p) break;
321 + char name[3]={0}; name[0]=toupper(*p++); if(isalnum(*p)) name[1]=toupper(*p++);
322 + if (data_pos>=data_count) { printf("?Out of DATA\n"); running=0; return; }
323 + var_vals[ptrget(name)] = data_pool[data_pos++];
324 + }
325 + return;
326 + }
327 + /* RESTORE */
328 + if (strncasecmp(p,"RESTORE",7)==0) { data_pos=0; return; }
329 + /* DATA */
330 + if (strncasecmp(p,"DATA",4)==0) return; /* handled at collect time */
331 + /* END / STOP */
332 + if (strncasecmp(p,"END",3)==0 || strncasecmp(p,"STOP",4)==0) { running=0; return; }
333 + /* LIST */
334 + if (strncasecmp(p,"LIST",4)==0) {
335 + for(int i=0;i<prog_cnt;i++) printf("%d %s\n",program[i].num,program[i].text);
336 + return;
337 + }
338 + /* RUN */
339 + if (strncasecmp(p,"RUN",3)==0) {
340 + collect_data(); data_pos=0; call_sp=0; for_sp=0; var_cnt=0;
341 + run_from(0); return;
342 + }
343 + /* NEW */
344 + if (strncasecmp(p,"NEW",3)==0) { prog_cnt=0; var_cnt=0; call_sp=0; for_sp=0; data_count=0; printf("Ok\n"); return; }
345 + /* CLEAR */
346 + if (strncasecmp(p,"CLEAR",5)==0) { var_cnt=0; call_sp=0; for_sp=0; data_pos=0; return; }
347 + /* DIM stub */
348 + if (strncasecmp(p,"DIM",3)==0) return;
349 +
350 + printf("?Syntax error\n");
351 + }
352 +
353 + /* Execute multiple statements on one line (: separated) */
354 + void execute_line(char *text) {
355 + char buf[MAXBUF]; strncpy(buf,text,MAXBUF-1);
356 + char *tok = strtok(buf,":");
357 + while (tok && running) {
358 + execute_stmt(tok);
359 + tok = strtok(NULL,":");
360 + }
361 + }
362 +
363 + /* RUN loop from line index */
364 + void run_from(int idx) {
365 + running = 1;
366 + cur_line_idx = idx;
367 + while (running && cur_line_idx < prog_cnt) {
368 + int save = cur_line_idx;
369 + execute_line(program[cur_line_idx].text);
370 + if (running == 2) { running = 1; } /* GOTO/GOSUB already set cur_line_idx */
371 + else if (running) cur_line_idx++;
372 + }
373 + running = 0;
374 + }
375 +
376 + /* ============================================================
377 + MAIN - READY loop
378 + ============================================================ */
379 + int main() {
380 + srand((unsigned)time(NULL));
381 + printf("MS BASIC-80 C Port\nOk\n");
382 + char input[MAXBUF];
383 + while (1) {
384 + printf("> ");
385 + if (!fgets(input,MAXBUF,stdin)) break;
386 + input[strcspn(input,"\n")] = 0;
387 + if (!*input) continue;
388 + /* Check for line number */
389 + char *p = input;
390 + skip_ws(&p);
391 + if (isdigit(*p)) {
392 + int num = (int)strtol(p,&p,10);
393 + skip_ws(&p);
394 + insert_line(num, *p ? p : "");
395 + } else {
396 + /* Direct statement */
397 + if (strncasecmp(p,"RUN",3)==0) { collect_data(); data_pos=0; call_sp=0; for_sp=0; var_cnt=0; run_from(0); }
398 + else if (strncasecmp(p,"LIST",4)==0) { for(int i=0;i<prog_cnt;i++) printf("%d %s\n",program[i].num,program[i].text); }
399 + else if (strncasecmp(p,"NEW",3)==0) { prog_cnt=0; var_cnt=0; call_sp=0; for_sp=0; data_count=0; }
400 + else execute_stmt(p);
401 + }
402 + printf("Ok\n");
403 + }
404 + return 0;
405 + }
Nowsze Starsze