1 {Unidad que implementa a la clase TParserAsm, que sirve como contenedor para
2 implementar las funcionaliddes de procesamiento de bloques ensamblador.
3 }
4 unit ParserAsm_PIC10;
5 {$mode objfpc}{$H+}
6 interface
7 uses
8 Classes, SysUtils, fgl, SynFacilHighlighter, Pic10Utils, GenCod_PIC10, Globales,
9 XpresBas, strutils, XpresElementsPIC;
10
11 type
12 //Datos de una etiqueta
13 TPicLabel = class
14 txt: string; //nombre de la etiqueta
15 add: integer; //dirección
16 end;
17 TPicLabel_list = specialize TFPGObjectList<TPicLabel>;
18
19 //Datos de una instrucción de salto, indefinido.
20 TPicUJump = class
21 txt: string; //nombre de la etiqueta
22 add: integer; //dirección
23 idInst: TPIC10Inst;
24 end;
25 TPicUJump_list = specialize TFPGObjectList<TPicUJump>;
26
27 { TParserAsm }
28 TParserAsm = class(TGenCod)
29 private
30 lexAsm : TSynFacilSyn; //lexer para analizar ASM
31 tokIni2 : integer; //Posición inicial del token actual
32 labels : TPicLabel_list; //Lista de etiquetas
33 uJumps : TPicUJump_list; //Lista de instrucciones GOTO o i_CALL, indefinidas
34 asmRow : integer; //número de fila explorada
35 procedure AddLabel(name: string; addr: integer);
36 procedure AddUJump(name: string; addr: integer; idInst: TPIC10Inst);
CaptureAddressnull37 function CaptureAddress(const idInst: TPIC10Inst; var a: word): boolean;
CaptureBitVarnull38 function CaptureBitVar(out f, b: byte): boolean;
CaptureBytenull39 function CaptureByte(out k: byte): boolean;
CaptureCommanull40 function CaptureComma: boolean;
CaptureDestinatnull41 function CaptureDestinat(out d: TPIC10destin): boolean;
CaptureNbitnull42 function CaptureNbit(var b: byte): boolean;
CaptureRegisternull43 function CaptureRegister(out f: byte): boolean;
44 procedure EndASM;
45 procedure GenErrorAsm(msg: string);
46 procedure GenErrorAsm(msg: string; const Args: array of const);
47 procedure GenWarnAsm(msg: string);
GetFaddressnull48 function GetFaddress(addr: integer): byte;
HaveByteInformationnull49 function HaveByteInformation(out bytePos: byte): boolean;
IsLabelnull50 function IsLabel(txt: string; out dir: integer): boolean;
IsStartASMnull51 function IsStartASM(var lin: string): boolean;
IsEndASMnull52 function IsEndASM(var lin: string): boolean;
53 procedure ProcASM(const AsmLin: string);
54 procedure ProcInstrASM;
55 procedure skipWhites;
56 procedure StartASM;
tokTypenull57 function tokType: integer;
58 protected
59 procedure ProcASMlime(const AsmLin: string);
60 public //Inicialización
61 constructor Create; override;
62 destructor Destroy; override;
63 end;
64
65 procedure SetLanguage;
66
67 implementation
68 var //Mensajes
69 ER_EXPEC_COMMA, ER_EXP_ADR_VAR, ER_EXP_CON_VAL, ER_NOGETADD_VAR,
70 ER_NOGETVAL_CON, ER_INV_ASMCODE: String;
71 ER_EXPECT_W_F, ER_SYNTAX_ERR_, ER_DUPLIC_LBL_, ER_EXPE_NUMBIT: String;
72 ER_EXPECT_ADDR, ER_EXPECT_BYTE, WA_ADDR_TRUNC, ER_UNDEF_LABEL_: String;
73
74 procedure SetLanguage;
75 begin
76 GenCod_PIC10.SetLanguage;
77 {$I ..\language\tra_ParserAsm.pas}
78 end;
79
80 { TParserAsm }
81 procedure TParserAsm.GenErrorAsm(msg: string);
82 {Genera un error corrigiendo la posición horizontal}
83 var
84 p: TSrcPos;
85 begin
86 p := cIn.ReadSrcPos;
87 p.col := tokIni2 + lexAsm.GetX; //corrige columna
88 GenErrorPos(msg, [], p);
89 end;
90 procedure TParserAsm.GenErrorAsm(msg: string; const Args: array of const);
91 var
92 p: TSrcPos;
93 begin
94 p := cIn.ReadSrcPos;
95 p.col := tokIni2 + lexAsm.GetX; //corrige columna
96 GenErrorPos(msg, Args, p);
97 end;
98 procedure TParserAsm.GenWarnAsm(msg: string);
99 {Genera una advertencia corrigiendo la posición horizontal}
100 var
101 p: TSrcPos;
102 begin
103 p := cIn.ReadSrcPos;
104 p.col := lexAsm.GetX; //corrige columna
105 GenWarnPos(msg, [], p);
106 end;
tokTypenull107 function TParserAsm.tokType: integer; inline;
108 begin
109 Result := lexAsm.GetTokenKind;
110 end;
111 procedure TParserAsm.skipWhites;
112 //salta blancos o comentarios
113 begin
114 if tokType = lexAsm.tnSpace then
115 lexAsm.Next; //quita espacios
116 //puede que siga comentario
117 if tokType = lexAsm.tnComment then
118 lexAsm.Next;
119 //después de un comentario no se espera nada.
120 end;
GetFaddressnull121 function TParserAsm.GetFaddress(addr: integer): byte;
122 {Obtiene una dirección de registro para una isntrucción ASM, truncando, si es necesario,
123 los bits adicionales.}
124 begin
125 if addr>255 then begin
126 addr := addr and $7F;
127 //Indica con advertencia
128 GenWarnAsm(WA_ADDR_TRUNC);
129 end;
130 Result := addr;
131 end;
132 procedure TParserAsm.AddLabel(name: string; addr: integer);
133 {Agrega una etiqueta a la lista}
134 var
135 lbl: TPicLabel;
136 begin
137 lbl := TPicLabel.Create;
138 lbl.txt:= UpCase(name);
139 lbl.add := addr;
140 labels.Add(lbl);
141 end;
142 procedure TParserAsm.AddUJump(name: string; addr: integer; idInst: TPIC10Inst);
143 {Agrega un salto indefinido a la lista}
144 var
145 jmp: TPicUJump;
146 begin
147 jmp := TPicUJump.Create;
148 jmp.txt:= UpCase(name);
149 jmp.add := addr;
150 jmp.idInst := idInst;
151 uJumps.Add(jmp);
152 end;
TParserAsm.IsLabelnull153 function TParserAsm.IsLabel(txt: string; out dir: integer): boolean;
154 {Indica si un nombre es una etiqueta. Si lo es, devuelve TRUE, y la dirección la retorna
155 en "dir".}
156 var
157 lbl: TPicLabel;
158 begin
159 //No se espera procesar muchsa etiquetas
160 for lbl in labels do begin
161 if lbl.txt = upcase(txt) then begin
162 dir := lbl.add;
163 exit(true);
164 end;
165 end;
166 //No encontró
167 exit(false);
168 end;
TParserAsm.HaveByteInformationnull169 function TParserAsm.HaveByteInformation(out bytePos: byte): boolean;
170 begin
171 // state0 := lexAsm.State; //gaurda posición
172 if lexasm.GetToken = '.' then begin
173 //Hay precisión de campo
174 lexAsm.Next;
175 if UpCase(lexasm.GetToken) = 'LOW' then begin
176 bytePos := 0;
177 lexAsm.Next;
178 exit(true);
179 end else if UpCase(lexasm.GetToken) = 'HIGH' then begin
180 bytePos := 1;
181 lexAsm.Next;
182 exit(true);
183 end else begin
184 //No es ninguno
185 exit(false);
186 end;
187 end else if lexasm.GetToken = '@' then begin
188 lexAsm.Next;
189 if UpCase(lexasm.GetToken) = '0' then begin
190 bytePos := 0;
191 lexAsm.Next;
192 exit(true);
193 end else if UpCase(lexasm.GetToken) = '1' then begin
194 bytePos := 1;
195 lexAsm.Next;
196 exit(true);
197 end else if UpCase(lexasm.GetToken) = '2' then begin
198 bytePos := 2;
199 lexAsm.Next;
200 exit(true);
201 end else if UpCase(lexasm.GetToken) = '3' then begin
202 bytePos := 3;
203 lexAsm.Next;
204 exit(true);
205 end else begin
206 //No es ninguno
207 exit(false);
208 end;
209 end else begin
210 //No tiene indicación de campo
211 exit(false);
212 end;
213 end;
CaptureBytenull214 function TParserAsm.CaptureByte(out k: byte): boolean;
215 {Captura un byte y devuelve en "k". Si no encuentra devuelve FALSE.}
216 var
217 n: Integer;
218 xcon: TxpEleCon;
219 ele: TxpElement;
220 bytePos: byte;
221 str: String;
222 xvar: TxpEleVar;
223 begin
224 Result := false;
225 skipWhites;
226 if tokType = lexAsm.tnNumber then begin
227 //es una dirección numérica
228 n := StrToInt(lexAsm.GetToken);
229 if (n>255) then begin
230 GenErrorAsm(ER_EXPECT_BYTE);
231 exit(false);
232 end;
233 k:=n;
234 lexAsm.Next;
235 exit(true);
236 end else if tokType = lexAsm.tnIdentif then begin
237 //Es un identificador, puede ser referencia a una constante o variable
238 ele := TreeElems.FindFirst(lexAsm.GetToken); //identifica elemento
239 if ele = nil then begin
240 //No identifica a este elemento
241 GenErrorAsm(ER_EXP_CON_VAL);
242 exit;
243 end;
244 if ele.idClass = eltCons then begin
245 xcon := TxpEleCon(ele);
246 AddCallerTo(xcon); //lleva la cuenta
247 if (xcon.typ = typByte) or (xcon.typ = typChar) then begin
248 k := xcon.val.ValInt;
249 lexAsm.Next;
250 exit(true);
251 end else if xcon.typ = typWord then begin
252 lexAsm.Next;
253 if HaveByteInformation(bytePos) then begin
254 //Hay precisión de byte
255 if bytePos = 0 then begin //Byte bajo
256 k := (xcon.val.ValInt and $FF);
257 end else begin //Byte alto
258 k := (xcon.val.ValInt and $FF00) >> 8;
259 end;
260 end else begin //No se indica byte
261 k := (xcon.val.ValInt and $FF);
262 end;
263 exit(true);
264 end else begin
265 GenErrorAsm(ER_NOGETVAL_CON);
266 exit(false);
267 end;
268 end else if ele.idClass = eltVar then begin
269 //Para varaibles, se toma la dirección
270 xvar := TxpEleVar(ele);
271 AddCallerTo(xvar); //lleva la cuenta
272 n := xvar.addr;
273 k := GetFaddress(n);
274 lexAsm.Next;
275 exit(true);
276 end else begin
277 //No es constante
278 GenErrorAsm(ER_EXP_CON_VAL);
279 exit(false);
280 end;
281 end else if (tokType = lexasm.tnString) and (length(lexAsm.GetToken) = 3) then begin
282 //Es un caracter
283 str := lexAsm.GetToken;
284 k := ord(str[2]); //lee código de caracter
285 lexAsm.Next;
286 exit(true);
287 end else begin
288 GenErrorAsm(ER_EXPECT_BYTE);
289 exit(false);
290 end;
291 end;
TParserAsm.CaptureDestinatnull292 function TParserAsm.CaptureDestinat(out d: TPIC10destin): boolean;
293 {Captura el destino de una instrucción y devuelve en "d". Si no encuentra devuelve error}
294 var
295 dest: String;
296 begin
297 skipWhites;
298 dest := lexAsm.GetToken;
299 if (LowerCase(dest)='f') or (dest='1') then begin
300 d := toF;
301 lexAsm.Next;
302 exit(true);
303 end else if (LowerCase(dest)='w') or (dest='0') then begin
304 d := toW;
305 lexAsm.Next;
306 exit(true);
307 end else begin
308 GenErrorAsm(ER_EXPECT_W_F);
309 exit(false);
310 end;
311 end;
TParserAsm.CaptureNbitnull312 function TParserAsm.CaptureNbit(var b: byte): boolean;
313 {Captura el número de bit de una instrucción y devuelve en "b". Si no encuentra devuelve error}
314 begin
315 skipWhites;
316 if tokType = lexAsm.tnNumber then begin
317 //es una dirección numérica
318 b := StrToInt(lexAsm.GetToken);
319 if (b>7) then begin
320 GenErrorAsm(ER_EXPE_NUMBIT);
321 exit(false);
322 end;
323 lexAsm.Next;
324 exit(true);
325 end else if tokType = lexAsm.tnIdentif then begin
326 //puede ser una constante
327 CaptureByte(b); //captura desplazamiento
328 if HayError then exit(false);
329 if (b>7) then begin
330 GenErrorAsm(ER_EXPE_NUMBIT);
331 exit(false);
332 end;
333 exit(true);
334 end else begin
335 GenErrorAsm(ER_EXPE_NUMBIT);
336 exit(false);
337 end;
338 end;
CaptureCommanull339 function TParserAsm.CaptureComma: boolean;
340 {Captura una coma. Si no encuentra devuelve error}
341 begin
342 skipWhites;
343 if lexAsm.GetToken = ',' then begin
344 lexAsm.Next; //toma la coma
345 Result := true;
346 exit;
347 end else begin
348 Result := false;
349 GenErrorAsm(ER_EXPEC_COMMA);
350 exit;
351 end;
352 end;
TParserAsm.CaptureBitVarnull353 function TParserAsm.CaptureBitVar(out f, b: byte): boolean;
354 {Captura una variable de tipo Bit. Si no encuentra, devuelve FALSE (no genera error).}
355 var
356 ele: TxpElement;
357 xvar: TxpEleVar;
358 begin
359 skipWhites;
360 if tokType <> lexAsm.tnIdentif then exit(false); //no es identificador
361 //Hay un identificador
362 ele := TreeElems.FindFirst(lexAsm.GetToken); //identifica elemento
363 if ele = nil then exit(false); //no se identifica
364 //Se identificó elemento
365 if ele.idClass <> eltVar then exit(false);
366 //Es variable
367 xvar := TxpEleVar(ele);
368 if not xvar.typ.IsBitSize then exit(false);
369 //Es variable bit o boolean
370 lexAsm.Next; //toma identificador
371 AddCallerTo(xvar); //lleva la cuenta
372 f := GetFaddress(xvar.adrBit.offs);
373 b := xvar.adrBit.bit;
374 exit(true);
375 end;
CaptureRegisternull376 function TParserAsm.CaptureRegister(out f: byte): boolean;
377 {Captura la referencia a un registro y devuelve en "f". Si no encuentra devuelve error}
378 var
379 n: integer;
380 ele: TxpElement;
381 xvar: TxpEleVar;
382 bytePos: byte;
383 begin
384 Result := false;
385 skipWhites;
386 if tokType = lexAsm.tnNumber then begin
387 //Es una dirección numérica
388 if not TryStrToInt(lexAsm.GetToken, n) then begin
389 GenErrorAsm(ER_SYNTAX_ERR_, [lexAsm.GetToken]);
390 exit;
391 end;
392 f := GetFaddress(n);
393 lexAsm.Next;
394 Result := true;
395 exit;
396 end else if lexAsm.GetToken = '_H' then begin
397 //Es el registro de trabajo _H
398 f := H_register.offs;
399 lexAsm.Next;
400 Result := true;
401 exit;
402 end else if lexAsm.GetToken = '_E' then begin
403 //Es el registro de trabajo _H
404 f := E_register.offs;
405 lexAsm.Next;
406 Result := true;
407 exit;
408 end else if lexAsm.GetToken = '_U' then begin
409 //Es el registro de trabajo _H
410 f := U_register.offs;
411 lexAsm.Next;
412 Result := true;
413 exit;
414 end else if tokType = lexAsm.tnIdentif then begin
415 //Es un identificador, puede ser referencia a una variable
416 ele := TreeElems.FindFirst(lexAsm.GetToken); //identifica elemento
417 if ele = nil then begin
418 //No identifica a este elemento
419 GenErrorAsm(ER_EXP_ADR_VAR);
420 exit;
421 end;
422 if ele.idClass = eltVar then begin
423 xvar := TxpEleVar(ele);
424 AddCallerTo(xvar); //lleva la cuenta
425 if xvar.typ.IsByteSize then begin
426 n := xvar.addr;
427 f := GetFaddress(n);
428 lexAsm.Next;
429 Result := true;
430 exit;
431 end else if xvar.typ.IsWordSize then begin
432 lexAsm.Next;
433 if HaveByteInformation(bytePos) then begin
434 //Hay precisión de byte
435 if bytePos = 0 then begin //Byte bajo
436 n := xvar.adrByte0.offs;
437 f := GetFaddress(n);
438 end else if bytePos = 1 then begin //Byte alto
439 n := xvar.adrByte1.offs;
440 f := GetFaddress(n);
441 end else begin
442 GenErrorAsm(ER_NOGETADD_VAR);
443 exit(false);
444 end;
445 end else begin
446 n := xvar.addr;
447 f := GetFaddress(n);
448 end;
449 exit(true);
450 end else if xvar.typ.IsDWordSize then begin
451 lexAsm.Next;
452 if HaveByteInformation(bytePos) then begin
453 //Hay precisión de byte
454 if bytePos = 0 then begin //Byte bajo
455 n := xvar.adrByte0.offs;
456 f := GetFaddress(n);
457 end else if bytePos = 1 then begin //Byte alto
458 n := xvar.adrByte1.offs;
459 f := GetFaddress(n);
460 end else if bytePos = 2 then begin //Byte alto
461 n := xvar.adrByte2.offs;
462 f := GetFaddress(n);
463 end else if bytePos = 3 then begin //Byte alto
464 n := xvar.adrByte3.offs;
465 f := GetFaddress(n);
466 end else begin
467 GenErrorAsm(ER_NOGETADD_VAR);
468 exit(false);
469 end;
470 end else begin
471 n := xvar.addr;
472 f := GetFaddress(n);
473 end;
474 exit(true);
475 end else begin
476 GenErrorAsm(ER_NOGETADD_VAR);
477 exit(false);
478 end;
479 end else begin
480 //No es variable
481 GenErrorAsm(ER_EXP_ADR_VAR);
482 Result := false;
483 exit;
484 end;
485 end else begin
486 GenErrorAsm(ER_EXP_ADR_VAR);
487 //asmErrLin := asmRow;
488 Result := false;
489 exit;
490 end;
491 end;
CaptureAddressnull492 function TParserAsm.CaptureAddress(const idInst: TPIC10Inst; var a: word
493 ): boolean;
494 {Captura una dirección a una instrucción y devuelve en "a". Si no encuentra genera
495 error y devuelve FALSE.}
496 var
497 dir: integer;
498 offset: byte;
499 ele: TxpElement;
500 xfun: TxpEleFun;
501 begin
502 Result := false;
503 skipWhites;
504 if lexAsm.GetToken = '$' then begin
505 //Es una dirección relativa
506 lexAsm.Next;
507 skipWhites;
508 //Puede tener + o -
509 if (lexAsm.GetToken= '') or (lexAsm.GetToken = ';') then begin
510 //Termina la instrucción sin o con es comentario
511 a := pic.iFlash;
512 Result := true;
513 exit;
514 end else if lexAsm.GetToken = '+' then begin
515 //Es dirección sumada
516 lexAsm.Next;
517 skipWhites;
518 CaptureByte(offset); //captura desplazamiento
519 if HayError then exit(false);
520 Result := true;
521 a := pic.iFlash + offset;
522 exit;
523 end else if lexAsm.GetToken = '-' then begin
524 //Es dirección restada
525 lexAsm.Next;
526 skipWhites;
527 CaptureByte(offset); //captura desplazamiento
528 if HayError then exit(false);
529 Result := true;
530 a := pic.iFlash - offset;
531 exit;
532 end else begin
533 //Sigue otra cosa
534 GenErrorAsm(ER_SYNTAX_ERR_, [lexAsm.GetToken]);
535 end;
536 end else if tokType = lexAsm.tnNumber then begin
537 //Es una dirección numérica
538 a := StrToInt(lexAsm.GetToken);
539 lexAsm.Next;
540 Result := true;
541 exit;
542 end else if (tokType = lexAsm.tnIdentif) and IsLabel(lexAsm.GetToken, dir) then begin
543 //Es un identificador de etiqueta
544 a := dir;
545 lexAsm.Next;
546 Result := true;
547 exit;
548 end else if tokType = lexAsm.tnIdentif then begin
549 ele := TreeElems.FindFirst(lexAsm.GetToken); //identifica elemento
550 if (ele <> nil) and (ele.idClass = eltFunc) then begin
551 //Es un identificador de función del árbol de sintaxis
552 xfun := TxpEleFun(ele);
553 AddCallerTo(xfun); //lleva la cuenta
554 a := xfun.adrr; //lee su dirección
555 lexAsm.Next;
556 Result := true;
557 exit;
558 end;
559 //Es un identificador, no definido. Puede definirse luego.
560 a := $00;
561 //Los saltos indefinidos, se guardan en la lista "uJumps"
562 AddUJump(lexAsm.GetToken, pic.iFlash, idInst);
563 lexAsm.Next;
564 Result := true;
565 exit;
566 end else begin
567 GenErrorAsm(ER_EXPECT_ADDR);
568 Result := false;
569 exit;
570 end;
571 end;
572 procedure TParserAsm.StartASM; //Inicia el procesamiento de código ASM
573 begin
574 asmRow := 1; //inicia línea
575 labels.Clear; //limpia etiquetas
576 uJumps.Clear;
577 end;
578 procedure TParserAsm.EndASM; //Termina el procesamiento de código ASM
579 var
580 jmp : TPicUJump;
581 loc: integer;
582 begin
583 //Completa los saltos indefinidos
584 if uJumps.Count>0 then begin
585 for jmp in uJumps do begin
586 if IsLabel(jmp.txt, loc) then begin
587 //Si existe la etiqueta
588 if jmp.idInst = i_GOTO then
589 pic.codGotoAt(jmp.add, loc)
590 else //Solo puede ser i_CALL
591 pic.codCallAt(jmp.add, loc);
592 end else begin
593 //No se enuentra
594 GenErrorAsm(ER_UNDEF_LABEL_, [jmp.txt]);
595 exit;
596 end;
597 end;
598 end;
599 end;
600 procedure TParserAsm.ProcInstrASM;
601 //Procesa una instrucción ASM
602 var
603 stx: string;
604 idInst: TPIC10Inst;
605 tok: String;
606 f : byte;
607 d: TPIC10destin;
608 b: byte;
609 a: word;
610 k: byte;
611 begin
612 tok := lexAsm.GetToken;
613 //verifica directiva ORG
614 if upcase(tok) = 'ORG' then begin
615 lexAsm.Next;
616 idInst := i_GOTO; //no debería ser necesario
617 if not CaptureAddress(idInst, a) then exit;
618 pic.iFlash := a; //¡CUIDADO! cambia PC
619 exit;
620 end;
621 //debería ser una instrucción
622 idInst := pic.FindOpcode(tok, stx);
623 if idInst = i_Inval then begin
624 GenErrorAsm(ER_INV_ASMCODE, [tok]);
625 exit;
626 end;
627 //es un código válido
628 lexAsm.Next;
629 case stx of
630 'fd': begin //se espera 2 parámetros
631 if not CaptureRegister(f) then exit;
632 if not CaptureComma then exit;
633 if not CaptureDestinat(d) then exit;
634 pic.codAsmFD(idInst, f, d);
635 end;
636 'f':begin
637 if not CaptureRegister(f) then exit;
638 pic.codAsmF(idInst, f);
639 end;
640 'fb':begin //para instrucciones de tipo bit
641 if CaptureBitVar(f, b) then begin
642 //Es una referencia a variable bit.
643 end else begin
644 if not CaptureRegister(f) then exit;
645 if not CaptureComma then exit;
646 if not CaptureNbit(b) then exit;
647 end;
648 pic.codAsmFB(idInst, f, b);
649 end;
650 'a': begin //i_CALL y GOTO
651 if not CaptureAddress(idInst, a) then exit;
652 pic.codAsmA(idInst, a);
653 end;
654 'k': begin //i_MOVLW
655 if not CaptureByte(k) then exit;
656 pic.codAsmK(idInst, k);
657 end;
658 '': begin
659 pic.codAsm(idInst);
660 end;
661 end;
662 //no debe quedar más que espacios o comentarios
663 skipWhites;
664 if tokType <> lexAsm.tnEol then begin
665 GenErrorAsm(ER_SYNTAX_ERR_, [lexAsm.GetToken]);
666 exit;
667 end;
668
669 end;
670 procedure TParserAsm.ProcASM(const AsmLin: string);
671 {Procesa una línea en ensamblador.}
ExtractLabelnull672 function ExtractLabel: boolean;
673 {Extrae una etiqueta en la posición actual del lexer. Si no identifica
674 a una etiqueta, devuelve FALSE.}
675 var
676 lbl: String;
677 state0: TFaLexerState;
678 d: integer;
679 begin
680 if tokType <> lexAsm.tnIdentif then
681 exit(false); //No es
682 //Guarda posición por si acaso
683 state0 := lexAsm.State;
684 //Evalúa asumiendo que es etiqueta
685 lbl := lexAsm.GetToken; //guarda posible etiqueta
686 lexAsm.Next;
687 if lexAsm.GetToken = ':' then begin
688 //Definitivamente es una etiqueta
689 if IsLabel(lbl, d) then begin
690 GenErrorAsm(ER_DUPLIC_LBL_, [lbl]);
691 exit(false);
692 end;
693 AddLabel(lbl, pic.iFlash);
694 lexAsm.Next;
695 skipwhites;
696 if tokType <> lexAsm.tnEol then begin
697 //Hay algo más. Solo puede ser una instrucción
698 ProcInstrASM;
699 if HayError then exit(false);
700 end;
701 exit(true);
702 end else begin
703 //No es etiqueta
704 lexAsm.State := state0; //recupera posición
705 exit(false)
706 end;
707 end;
708 begin
709 inc(asmRow); //cuenta líneas
710 if Trim(AsmLin) = '' then exit;
711 //procesa la destínea
712 lexAsm.SetLine(asmLin, asmRow); //inicia cadena
713 if tokType = lexAsm.tnKeyword then begin
714 ProcInstrASM;
715 if HayError then exit;
716 end else if Extractlabel then begin
717 //Era una etiqueta
718 end else if tokType = lexAsm.tnComment then begin
719 skipWhites;
720 if tokType <> lexAsm.tnEol then begin
721 GenErrorAsm(ER_SYNTAX_ERR_, [lexAsm.GetToken]);
722 exit;
723 end;
724 end else if tokType = lexAsm.tnSpace then begin
725 skipWhites;
726 if tokType <> lexAsm.tnEol then begin
727 //Hay algo más. Solo puede ser una instrucción o etiqueta
728 if tokType = lexAsm.tnKeyword then begin
729 //Es instrucción
730 ProcInstrASM;
731 if HayError then exit;
732 end else if Extractlabel then begin
733 //Era una etiqueta
734 end else begin
735 //Es otra cosa
736 GenErrorAsm(ER_SYNTAX_ERR_, [lexAsm.GetToken]);
737 exit;
738 end;
739 end;
740 end else begin
741 GenErrorAsm(ER_SYNTAX_ERR_, [lexAsm.GetToken]);
742 exit;
743 end;
744 skipWhites; //quita espacios
745 // msgbox(AsmLin);
746 end;
IsStartASMnull747 function TParserAsm.IsStartASM(var lin: string): boolean;
748 {Indica si una línea contiene al delimitador inicial "ASM". Si es así, la recorta.}
749 begin
750 if not AnsiStartsText('asm', lin) then
751 exit(false); //definitivamente no es
752 //hay coincidencia pero hay que analziar más
753 if length(lin) = 3 then begin
754 lin := copy(lin, 4, length(lin)); //quita "asm"
755 exit(true); //es exacto
756 end;
757 //podrìa ser, pero hay que descartar que no sea parte de un identificador
758 if lin[4] in ['a'..'z', 'A'..'Z', '0'..'9', '_'] THEN
759 exit(false); //es parte de un identificador
760 //es por descarte
761 lin := copy(lin, 4, length(lin)); //quita "asm"
762 exit(true);
763 end;
TParserAsm.IsEndASMnull764 function TParserAsm.IsEndASM(var lin: string): boolean;
765 {Indica si una línea contiene al delimitador final "END". Si es así, la recorta.}
766 begin
767 if not AnsiEndsText('end', lin) then
768 exit(false); //definitivamente no es
769 //Hay coincidencia pero hay que analziar más
770 if length(lin) = 3 then begin
771 lin := copy(Lin, 1, length(Lin)-3); //quita "end"
772 exit(true); //es exacto
773 end;
774 //Podrìa ser, pero hay que descartar que no sea parte de un identificador
775 if lin[length(lin)-3] in ['a'..'z', 'A'..'Z', '0'..'9', '_'] THEN
776 exit(false); //es parte de un identificador
777 //Es por descarte
778 lin := copy(Lin, 1, length(Lin)-3); //quita "end"
779 exit(true);
780 end;
781 procedure TParserAsm.ProcASMlime(const AsmLin: string);
782 {Procesa una línea de código ASM. Notar que los bloques ASM pueden tener muchas líneas
783 pero el procesamiento, se hace siempre línea por línea, debido a cómo trabaja el
784 lexer.}
785 var
786 lin: String;
787 begin
788 lin := AsmLin; //crea copia para poder modificarla
789 //Extrae el texto entre los delimitadores de ensamblador
790 if IsStartASM(lin) then begin
791 //Como se ha recortado el "ASM", se debe compensar "tokIni2"
792 //Además se debe considerar si el delim. ASM, no inicia en 1.
793 tokIni2 := 3 + Cin.curCon.lex.GetX - 1;
794 //Es la primera línea de ensamblador
795 StartASM;
796 //puede incluir también al delimitador "end"
797 if IsEndASM(lin) then begin
798 ProcASM(lin); //procesa por si queda código
799 EndASM;
800 end else begin
801 ProcASM(lin); //procesa por si queda código
802 end;
803 end else if IsEndASM(lin) then begin
804 //Es la última línea de ensamblador
805 tokIni2 := 0; //En el margen izquierdo, porque no está el delimit. inicial "ASM"
806 ProcASM(lin); //procesa por si queda código
807 EndASM;
808 end else begin
809 //Es una línea común
810 tokIni2 := 0; //una línea común, siempre empieza en al margen izquierdo
811 ProcASM(lin);
812 end;
813 end;
814 constructor TParserAsm.Create;
815 begin
816 inherited Create;
817 labels := TPicLabel_list.Create(true);
818 uJumps := TPicUJump_list.Create(true);
819 {Define la sintaxis del lexer que se usará para analizar el código en ensamblador.}
820 lexAsm := TSynFacilSyn.Create(nil); //crea lexer para analzar ensamblador
821 lexAsm.DefTokIdentif('[A-Za-z_]', '[A-Za-z0-9_]*');
822 lexAsm.DefTokContent('[0-9]', '[0-9.]*', lexAsm.tnNumber);
823 lexAsm.DefTokContent('[$]','[0-9A-Fa-f]*', lexAsm.tnNumber);
824 lexAsm.DefTokContent('[%]','[01]*', lexAsm.tnNumber);
825 lexAsm.AddIdentSpecList('ADDWF ANDWF CLRF CLRW COMF DECF DECFSZ INCF', lexAsm.tnKeyword);
826 lexAsm.AddIdentSpecList('INCFSZ IORWF MOVF MOVWF NOP RLF RRF SUBWF SWAPF XORWF', lexAsm.tnKeyword);
827 lexAsm.AddIdentSpecList('BCF BSF BTFSC BTFSS', lexAsm.tnKeyword);
828 lexAsm.AddIdentSpecList('ADDLW ANDLW CALL CLRWDT GOTO IORLW MOVLW RETFIE', lexAsm.tnKeyword);
829 lexAsm.AddIdentSpecList('RETLW RETURN SLEEP SUBLW XORLW', lexAsm.tnKeyword);
830 lexAsm.AddIdentSpecList('OPTION TRIS MOVLB', lexAsm.tnKeyword);
831 lexAsm.AddIdentSpecList('ORG', lexAsm.tnKeyword);
832 lexAsm.DefTokDelim(';','', lexAsm.tnComment);
833 lexAsm.DefTokDelim('''','''', lexAsm.tnString);
834 lexAsm.Rebuild;
835 end;
836 destructor TParserAsm.Destroy;
837 begin
838 lexAsm.Destroy;
839 uJumps.Destroy;
840 labels.Destroy;
841 inherited Destroy;
842 end;
843
844 end.
845
846