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