Última atividade 1 month ago

basic.c Bruto
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 ---- */
16typedef struct { int num; char text[MAXBUF]; } Line;
17Line program[MAXLINES];
18int prog_cnt = 0;
19
20/* ---- variables (numeric only for now) ---- */
21char var_names[MAXVARS][3];
22double var_vals[MAXVARS];
23int var_cnt = 0;
24
25/* ---- DATA pool ---- */
26double data_pool[MAXDATA];
27int data_count = 0;
28int data_pos = 0;
29
30/* ---- GOSUB stack (BAKSTK) ---- */
31int call_stack[MAXSTACK];
32int call_sp = 0;
33
34/* ---- FOR/NEXT stack ---- */
35typedef struct { int var_idx; double limit; double step; int line_idx; } ForEntry;
36ForEntry for_stack[MAXSTACK];
37int for_sp = 0;
38
39/* ---- globals ---- */
40double fac;
41int cur_line_idx; /* index into program[] */
42int running;
43
44/* ============================================================
45 FIND_LINE - like SRCHLN
46 ============================================================ */
47int 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 ============================================================ */
56int 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 ============================================================ */
71double expr(char **p);
72
73static void skip_ws(char **p) { while (**p == ' ') (*p)++; }
74
75static 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
111static 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
118static 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
130double 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 */
143double 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 ============================================================ */
158void 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 ============================================================ */
180void 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 ============================================================ */
207void execute_line(char *stmt);
208void run_from(int idx);
209
210void 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) */
354void 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 */
364void 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 ============================================================ */
379int 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}