uPreBasicos.pas 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369
  1. {**********************************************************************************
  2. uPreBasicos
  3. Unidad con las definiciones y funciones básicas para el tratamiento de los errores
  4. y contextos del pre-procesador PreSQL.
  5. Un contexto es una abstracción de datos materializada en una estructura que
  6. permite almacenar texto, generalmente destinado a ser preprocesado por el PreSQL.
  7. En el contexto se tiende considera siempre, el salto de línea como si fuera
  8. un sólo caracter porque se lee con una sola llamada a las funciones VerCar() y
  9. CogCar().
  10. En el tratamiento del contexto, se asume que todas las líneas, excepto la
  11. última, tienen un caracter FIN_LIN como delimitador final.
  12. Esta unidad se ha adaptado del código Visual Basic del PreSQL 1.3.
  13. Adaptado Por Tito Hinostroza 23/08/2013
  14. ***********************************************************************************
  15. }
  16. unit uPreBasicos; {$mode objfpc}{$H+}
  17. interface
  18. uses Classes, SysUtils, Fgl;
  19. Const
  20. FIN_LIN = #13; //Fin de línea
  21. FIN_CON = #0; //Fin de contexto
  22. //Tipos de contextos
  23. TC_ARC = 0 ; //contexto de tipo archivo
  24. TC_TXT = 1 ; //contexto de tipo texto
  25. Type
  26. //Tipo de operando
  27. TPTipOper = (TIP_DES, //tipo desconocido
  28. TIP_NUM, //tipo número
  29. TIP_CAD); //tipo cadena
  30. //Categoría para clasificar a los operandos
  31. TPCatOper = (COP_VACIO, //Operando nulo
  32. // COP_VARPUNTO, //Variable Punto
  33. COP_DEFINIC, //es una variable (definición)
  34. COP_FUNCION, //Es una función
  35. COP_CONST, //Es una constante
  36. COP_EXPRESION); //Es resultado de una expresión
  37. //Tipo expresión. Se usa para manejo de evaluación aritmética.
  38. { Texpre }
  39. Texpre = object //Tipo expresión
  40. txt: String; //Texto de la expresión
  41. tip: TPTipOper; //Tipo de dato que devuelve la expresión
  42. cat: TPCatOper; //Categoría de expresión
  43. // uop: String ; //último operador que se ejecutó de la expresión
  44. private
  45. fTxt: String; //Valor numérico de la expresión
  46. fNum: Single; //Valor numérico de la expresión
  47. procedure FijTxt(txt0: string);
  48. function LeeTxt: string;
  49. procedure FijNum(n0: single);
  50. function LeeNum: single;
  51. function LeeFec: TDateTime;
  52. public
  53. def : pointer; //referencia a la definición (en caso de que lo sea)
  54. property valTxt: string read LeeTxt write FijTxt;
  55. property valNum: single read LeeNum write FijNum;
  56. property valFec: TDateTime read LeeFec;
  57. End;
  58. //ID para categorizar a los tokens
  59. TtkTokenKind = (tkComment, tkIdentifier, tkKey, tkNull, tkNumber, tkSpace, tkString,
  60. tkUnknown, tkMacro);
  61. TContexto = class;
  62. {Posición dentro de un contexto. A diferecnia de "Tcontexto", es un registro y siempre
  63. guardará una copia permanente. Además no guarda el texto del contexto}
  64. TPosCont = record
  65. arc : String ; //Nombre de archivo
  66. fil : LongInt ; //Fila
  67. col : Integer ; //Columna
  68. nlin : LongInt ; //Número de líneas
  69. fCon : TContexto; //Referencia al Contexto
  70. End;
  71. { TPError }
  72. {Define al objeto PError, el que se usa para tratar los errores del preprocesador. Solo se
  73. espera que haya uno de estos objetos, por eso se ha declarado como OBJECT}
  74. TPError = object
  75. private
  76. numER : Integer; //codigo de error
  77. arcER : String; //nombre de archivo que origino el error
  78. fil : integer; //número de línea del error
  79. col : integer; //número de columna del error
  80. public
  81. cadError : String; //cadena de error
  82. NombPrograma: string; //Usado para poner en el encabezado del mensaje
  83. procedure IniError;
  84. procedure GenError(num: Integer; msje : String; archivo: String = ''; nlin: integer = 0);
  85. procedure GenError(msje: String; posCon: TPosCont);
  86. function GenTxtError: string;
  87. // procedure MosError;
  88. function ArcError: string;
  89. function nLinError: longint;
  90. Function nColError: longint;
  91. function HayError: boolean;
  92. end;
  93. { TContexto }
  94. {Estructura que define a un objeto contexto. Se usa tanto para leer la entrada como para
  95. escribir en la salida.}
  96. TContexto = class
  97. tip : integer;
  98. arc : String; //nombre de archivo
  99. fil : LongInt; //fila actual
  100. col : Integer; //columna actual
  101. nlin : LongInt; //Número de líneas del Contexto
  102. lin : TStringList; {Líneas de texto. Se almacena en TStringList porque es rápida la
  103. carga desde un archivo y porque es compatible con el almacenamiento
  104. en el Control Editor.}
  105. constructor Create;
  106. destructor Destroy; override;
  107. //Métodos de lectura
  108. Function IniCont:Boolean;
  109. Function FinCont:Boolean;
  110. Function VerCar:Char;
  111. Function CogCar:Char;
  112. Function VerCarAnt: Char;
  113. Function VerCarSig: Char;
  114. Function CapBlancos:Boolean;
  115. //Métodos de escritura
  116. procedure CurPosIni;
  117. procedure CurPosFin;
  118. procedure PonSalto; //Agrega Salto de línea
  119. procedure SacLinea; //quita la última línea
  120. procedure PonCar(c: char); //Agrega caracter
  121. procedure PonCad(s: String); //Agrega cadena
  122. procedure SacCar; //Quita un caracter
  123. //Métodos de llenado/lectura
  124. function LeeCad: string; //Lee el contenido del contexto
  125. procedure FijCad(cad : string); //Fija el contenido del contexto con cadena
  126. procedure FijArc(arc0: string); //Fija el contenido del contexto con archivo
  127. End;
  128. //Define una lista de Contextos
  129. TListaCont = specialize TFPGObjectList<TContexto>;
  130. { TPPro }
  131. TPPro = object
  132. private
  133. Function LeePosContAct: TPosCont;
  134. procedure FijPosContAct(pc:TPosCont);
  135. function LeeCadSal: String;
  136. procedure FijCadSal(cad: string);
  137. public
  138. constructor Create;
  139. destructor Destroy; //override;
  140. procedure Iniciar; //Prepara la secuencia de preprocesamiento
  141. //rutinas de entrada
  142. procedure NuevoContexEntTxt(txt: string; arc0: String);
  143. procedure NuevoContexEntArc(arc0: String);
  144. procedure QuitaContexEnt; //quita contexto de entrada actual
  145. //rutinas basicas de lectura
  146. Function IniCont:Boolean;
  147. Function FinCont:Boolean;
  148. Function VerCar: Char;
  149. Function VerCarN(numcar:Integer): String;
  150. Function CogCar:Char;
  151. // Function VerCarAnt:Char;
  152. Function CapBlancos:Boolean;
  153. function Capturar(cap: String): Boolean;
  154. property PosAct: TPosCont read LeePosContAct write FijPosContAct;
  155. //rutinas avanzadas de lectura
  156. Function VerIdentificador:String;
  157. Function VerIdentifM:String; //VE identificador en mayúscula
  158. Function VerPalabra():String;
  159. Function VerElemento():String;
  160. Function CogIdentificador:String;
  161. function CogIdentificador(var ide, ideM: string; var uc: char): boolean;
  162. function CogIdentificador(var ideM: string): boolean;
  163. Function cogPalabra():String;
  164. Function CogElemento():String;
  165. Function CogNumero:Single;
  166. Function CogNumero(var n:Single):boolean;
  167. Function CogCadena:String;
  168. Function CogCadena(var s: string):boolean;
  169. Function coger_ruta():String;
  170. function TipoSigToken: TtkTokenKind; //Devuelve el tipo del siguiente token
  171. Function VerSiEsComentario():Boolean;
  172. Function CogerHastaFinLinea():String;
  173. Function CogerHastaComent():String;
  174. Function VerHastaFinLinea():String;
  175. function CogerComent: boolean;
  176. function CogerLista(lista: TStringList; delims: string): string;
  177. function cogOperador: String; //coge operador
  178. function jerOp(oper: String): Integer; //jerarquía de operador
  179. function Evaluar(Op1: Texpre; opr: String; Op2: Texpre): Texpre;
  180. //rutinas de salida
  181. procedure NuevoContexSal; //Crea nuevo contexto de salida actual
  182. procedure QuitaContexSal; //quita contexto de salida actual
  183. procedure PonCar(c: char); //Agrega caracter
  184. procedure Escribe(palabra: string);
  185. procedure EscribeSalto;
  186. procedure SacCar;
  187. procedure GenArchivo(ArcSal0: string); //Genera archivo de salida
  188. function TextSalida: string; //Devuelve el texto preprocesado
  189. property cadenaSal: String read LeeCadSal write FijCadSal; //Cadena se salida del contexto actual
  190. private
  191. ConsE: TListaCont; //Lista de contextos de entrada
  192. ConsS: TListaCont; //Lista de contextos de salida
  193. //Variables del Contexto actual
  194. cEnt : TContexto; //referencia al contexto de entrada actual
  195. cSal : TContexto; //referencia al contexto de salida actual
  196. end;
  197. var
  198. PErr : TPError; //Objeto de Error
  199. PPro : TPPro; //Objeto Pre-Procesador
  200. ////////////////////////////////////////////////////////////////////////////////////////////
  201. implementation
  202. //caracteres iniciales válidos para idntificador
  203. { TODO : Debe desaparecer porque debe poder identificarse el token en la función "TipoSiguienteToken" }
  204. const CAR_INI_IDENT = ['$','a'..'z','A'..'Z','_']; //No se incluye 'ñ'
  205. //caracteres válidos para idntificador
  206. const CAR_IDENT = ['$','a'..'z','A'..'Z','_','0'..'9']; //No se incluye 'ñ'
  207. //caracteres válidos para idntificador
  208. const CAR_VAL_PALABRA = ['$','a'..'z','A'..'Z','_','0'..'9','.']; //¿'ñ'?
  209. { Texpre }
  210. procedure Texpre.FijTxt(txt0: string);
  211. //Fija valor de texto de un operando
  212. begin
  213. tip := TIP_CAD; //se fija como cadeana, de otra forma no podría recibir este valor
  214. fTxt := txt0;
  215. end;
  216. function Texpre.LeeTxt: string;
  217. //Lee la variable como texto
  218. begin
  219. if tip = TIP_CAD then //si ya es texto, la lectura es directa
  220. Result := ftxt
  221. else if tip = TIP_NUM then //Si es numérico, se hace una transformación
  222. //siempre se podrá transformar
  223. Result := FloatToStr(fNum) //pero no deja de ser numérico
  224. else
  225. Result := '';
  226. end;
  227. procedure Texpre.FijNum(n0: single);
  228. begin
  229. tip := TIP_NUM; //se fija como número, de otra forma no podría recibir este valor
  230. fNum := n0;
  231. end;
  232. function Texpre.LeeNum: single;
  233. begin
  234. if tip = TIP_CAD then begin //si es texto, se hace una transformación
  235. //puede que no se pueda transformar
  236. if not TryStrToFloat(trim(ftxt), Result) then //pero no deja de ser texto
  237. PErr.GenError( 1, 'Número inválido.')
  238. end else if tip = TIP_NUM then //Si ya es numérico, la lectura es directa
  239. Result := fNum
  240. else
  241. Result := 0;
  242. end;
  243. function Texpre.LeeFec: TDateTime;
  244. begin
  245. if tip = TIP_CAD then begin //si es texto, se hace una transformación
  246. //puede que no se pueda transformar
  247. ftxt := trim(ftxt);
  248. if not TryStrToDateTime(ftxt, Result) then //pero no deja de ser texto
  249. PErr.GenError( 1, 'Fecha inválida.')
  250. end else if tip = TIP_NUM then //Si ya es numérico, la lectura es directa
  251. Result := fNum
  252. else
  253. Result := 0;
  254. end;
  255. { TPPro }
  256. constructor TPPro.Create;
  257. begin
  258. //Crea lista de Contextos
  259. ConsE := TListaCont.Create(true); //crea contenedor de Contextos, con control de objetos.
  260. cEnt := nil;
  261. ConsS := TListaCont.Create(true); //crea contenedor de Contextos con control.
  262. cSal := nil;
  263. end;
  264. destructor TPPro.Destroy;
  265. begin
  266. //Limpia lista de Contextos
  267. ConsE.Free;
  268. //Limpia Contextos de salida
  269. ConsS.Free;
  270. end;
  271. procedure TPPro.Iniciar;
  272. //Inicia la maquinaria de manejo de Contextos
  273. begin
  274. ConsE.Clear; //elimina todos los Contextos de entrada
  275. ConsS.Clear; //elimina
  276. end;
  277. procedure TPPro.NuevoContexEntTxt(txt: string; arc0: String);
  278. //Crea un Contexto a partir de una cadena.
  279. //Fija el Contexto Actual "cEnt" como el Contexto creado.
  280. begin
  281. cEnt := TContexto.Create; //crea Contexto
  282. ConsE.Add(cEnt); //Registra Contexto
  283. cEnt.FijCad(txt); //inicia con texto
  284. cEnt.arc := arc0; {Se guarda el nombre del archivo actual, solo para poder procesar
  285. las funciones $NOM_ACTUAL y $DIR_ACTUAL}
  286. cEnt.CurPosIni; //posiciona al inicio
  287. end;
  288. procedure TPPro.NuevoContexEntArc(arc0: String);
  289. //Crea un Contexto a partir de un archivo. Devuelve el manejador del Contexto
  290. //Fija el Contexto Actual "cEnt" como el Contexto creado.
  291. begin
  292. If not FileExists(arc0) Then begin //ve si existe
  293. PErr.GenError( 1, 'No se encuentra archivo: ' + arc0);
  294. Exit;
  295. end;
  296. cEnt := TContexto.Create; //crea Contexto
  297. ConsE.Add(cEnt); //Registra Contexto
  298. cEnt.FijArc(arc0); //inicia con archivo
  299. cEnt.CurPosIni; //posiciona al inicio
  300. end;
  301. procedure TPPro.QuitaContexEnt;
  302. //Elimina el contexto de entrada actual. Deja apuntando al anterior en la misma posición.
  303. begin
  304. if ConsE.Count = 0 then exit; //no sep uede quitar más
  305. ConsE.Delete(ConsE.Count-1);
  306. if ConsE.Count = 0 then
  307. cEnt := nil
  308. else //apunta al último
  309. CEnt := ConsE[ConsE.Count-1];
  310. end;
  311. function TPPro.LeePosContAct: TPosCont;
  312. //Devuelve Contexto actual y su posición
  313. begin
  314. Result.fCon := cEnt;
  315. if cEnt = nil then begin
  316. //aún no hay Contexto definido
  317. Result.fil := 1;
  318. Result.col := 1;
  319. Result.arc := '';
  320. Result.nlin := 0;
  321. end else begin
  322. Result.fil := cEnt.fil;
  323. Result.col := cEnt.col;
  324. Result.arc := cEnt.arc;
  325. Result.nlin := cEnt.nlin;
  326. end;
  327. End;
  328. procedure TPPro.FijPosContAct(pc:TPosCont);
  329. //Fija Contexto actual y su posición
  330. begin
  331. cEnt := pc.fCon;
  332. if cEnt = nil then begin
  333. //no tiene un Contexto actual
  334. // filAct := 1;
  335. // colAct := 1;
  336. // cEnt.arc := '';
  337. // nlin := 0;
  338. end else begin
  339. cEnt.fil := pc.fil;
  340. cEnt.col := pc.col;
  341. cEnt.arc := pc.arc;
  342. cEnt.nlin := pc.nlin;
  343. end;
  344. End;
  345. function TPPro.LeeCadSal: String;
  346. //Devuelve la cadena equivalente del contexto de salida actual
  347. begin
  348. Result := cSal.LeeCad;
  349. end;
  350. procedure TPPro.FijCadSal(cad: string);
  351. //Fija la cadena equivalente del contexto de salida actual
  352. begin
  353. cSal.FijCad(cad);
  354. end;
  355. //********************************************************************************
  356. //Funciones Básicas de acceso al Contexto actual. Todo acceso al Contexto actual
  357. //debe hacerse a través de estas funciones por seguridad.
  358. //********************************************************************************
  359. function TPPro.IniCont: Boolean;
  360. //Devuelve verdadero si se está al inicio del Contexto actual (fila 1, columna 1)
  361. begin
  362. Result := cEnt.IniCont;
  363. End;
  364. function TPPro.FinCont: Boolean;
  365. //Devuelve verdadero si se ha pasado del final del Contexto actual
  366. begin
  367. Result := cEnt.FinCont;
  368. End;
  369. function TPPro.VerCar: Char;
  370. //Devuelve el caracter actual a partir de la posición actual, del Contexto actual.
  371. //Si no hay texto en el Contexto actual o si se ha llegado al final del
  372. //texto, devuelve FIN_CON.
  373. //Si está al final de una línea devuelve siempre "FIN_LIN"
  374. begin
  375. Result := cEnt.VerCar;
  376. End;
  377. function TPPro.VerCarN(numcar: Integer): String;
  378. //Devuelve los N caracteres a partir de la posición actual, del Contexto actual.
  379. //Si no hay texto en el Contexto actual o si se ha llegado al final del
  380. //texto, devuelve FIN_CON.
  381. //Si está al final de una línea devuelve siempre "FIN_LIN"
  382. var linact:String;
  383. begin
  384. If FinCont Then Exit(FIN_CON);
  385. linact := cEnt.lin[cEnt.fil-1]; //línea actual
  386. If cEnt.col = Length(linact) + 1 Then begin
  387. //Se está al fin de la línea. Se considera que cada línea
  388. //tiene un salto de línea al final, excepto la última línea.
  389. //En este caso siempre se devuelve FIN_LIN
  390. Result := FIN_LIN
  391. end Else //No se está al fin de la línea
  392. Result := copy(linact, cEnt.col, numcar);
  393. End;
  394. function TPPro.CogCar: Char;
  395. //Devuelve el caracter actual del Contexto actual e incrementa
  396. //el puntero a la siguiente posición.
  397. //La siguiente posición del fin de una línea es el caracter "salto de
  398. //línea", que son en realidad dos caracteres.
  399. begin
  400. Result :=cEnt.CogCar;
  401. End;
  402. {Function TPPro.VerCarAnt: Char;
  403. //echa un vistazo al caracter anterior del Contexto
  404. //Si no hay caracter anterior, devuelve cadena vacía
  405. Var linact:String;
  406. begin
  407. Result := #0;
  408. If cEnt.FinCont Then Exit; //Realmente debería devolver el caracter final
  409. If IniCont Then Exit; //No hay caracter anterior
  410. linact := cEnt.lin[cEnt.fil-1]; //línea actual
  411. If cEnt.col = 1 Then
  412. //Está al inicio de una línea
  413. Result := FIN_LIN //devuelve el salto anterior
  414. Else
  415. Result := linact[cEnt.col-1];
  416. End;}
  417. function TPPro.CapBlancos: Boolean;
  418. //Coge los blancos iniciales del contexto de entrada.
  419. //Si no encuentra algun blanco al inicio, devuelve falso
  420. begin
  421. Result := cEnt.CapBlancos;
  422. End;
  423. function TPPro.Capturar(cap: String): Boolean;
  424. //coge la cadena dada ignorando los blancos iniciales.
  425. Var i:Integer;
  426. begin
  427. Result := False;
  428. cEnt.CapBlancos; //quita blancos iniciales
  429. i := 1;
  430. While Not cEnt.FinCont And (i <= Length(cap)) do begin
  431. If cEnt.VerCar = cap[i] Then begin
  432. cEnt.CogCar;
  433. i := i + 1;
  434. end Else
  435. Exit; //fallo en algun caracter
  436. End;
  437. If i > Length(cap) Then //encontró toda la cadena
  438. Capturar := True;
  439. End;
  440. //********************************************************************************
  441. //Funciones de mayor nivel para acceso al Contexto actual.
  442. //********************************************************************************
  443. function TPPro.VerIdentificador: String;
  444. //devuelve una palabra correspondiente a un identificador
  445. //empieza a buscar desde el principio
  446. Var col0:Integer;
  447. begin
  448. col0 := cEnt.col;
  449. VerIdentificador := CogIdentificador;
  450. cEnt.col := col0;
  451. End;
  452. function TPPro.VerIdentifM: String;
  453. //Devuleve el dientificador en mayúscula
  454. begin
  455. Result := UpCase(VerIdentificador);
  456. end;
  457. function TPPro.VerPalabra: String;
  458. //devuelve una palabra correspondiente a un identificador
  459. //empieza a buscar desde el principio
  460. Var ncolTmp:Integer;
  461. begin
  462. ncolTmp := cEnt.col;
  463. VerPalabra := cogPalabra;
  464. cEnt.col := ncolTmp;
  465. End;
  466. function TPPro.VerElemento: String;
  467. //devuelve una palabra correspondiente a un identificador
  468. //empieza a buscar desde el principio
  469. Var fil0, col0: integer;
  470. begin
  471. col0 := cEnt.col; //guarda todo el contexto, porque "CogElemento", puede cambiar de línea
  472. fil0 := cEnt.fil;
  473. VerElemento := CogElemento;
  474. cEnt.col := col0; //recupera
  475. cEnt.fil := fil0;
  476. End;
  477. function TPPro.CogIdentificador: String;
  478. //Coge una palabra correspondiente a un identificador desde la posicion actual del
  479. //contexto.
  480. Var temp:String;
  481. car1, car: char;
  482. begin
  483. Result := ''; //no hay identificador inicialmente
  484. //CapBlancos; //no debe eliminar espacios
  485. temp := '';
  486. car1 := VerCar; //lee caracter inicial
  487. If FinCont Then Exit; //Fin de Contexto
  488. If Not (car1 in CAR_INI_IDENT) Then //primer caracter valido
  489. Exit; //no es identificador
  490. temp += CogCar; //acumula
  491. //busca hasta encontar fin de identificador
  492. car := VerCar;
  493. While car in CAR_IDENT do begin
  494. if (car = '$') then begin //verifica regla de nombre de identif.
  495. //verifica si es delimitador o inicio de otro identificador
  496. if (car1='$') then //es delimitador
  497. temp += CogCar; //acumula
  498. break;
  499. end;
  500. temp += CogCar; //acumula
  501. car := VerCar;
  502. end;
  503. //se llego al final del archivo
  504. Result := temp //copia hasta el final
  505. End;
  506. function TPPro.CogIdentificador(var ide, ideM: string; var uc:char): boolean;
  507. {Versión que lee el identificador normal y en mayúscula. Si no encuentra ningún identificador
  508. devuelve FALSE. Devuelve además el último caracter leido antes del identificador (uc).}
  509. begin
  510. if TipoSigToken = tkIdentifier then begin
  511. uc := cEnt.VerCarAnt; //lee caracter anterior
  512. ide := CogIdentificador();
  513. ideM := UpCase(ide); //en mayúscula
  514. exit(true); //sale con TRUE
  515. end else //no hay identificador
  516. exit(false);
  517. end;
  518. function TPPro.CogIdentificador(var ideM: string): boolean;
  519. //Versión sencilal que devuelve el identificador en mayúscula
  520. begin
  521. if TipoSigToken = tkIdentifier then begin
  522. ideM := UpCase(CogIdentificador()); //en mayúscula
  523. exit(true); //sale con TRUE
  524. end else //no hay identificador
  525. exit(false);
  526. end;
  527. function TPPro.cogPalabra: String;
  528. //coge una palabra completa (alfanumerico y punto decimal)
  529. //desde la posicion donde se encuentra el archivo
  530. Var temp:String;
  531. car:char;
  532. begin
  533. cogPalabra := ''; //no hay identificador inicialmente
  534. CapBlancos; //quita blancos iniciales
  535. temp := '';
  536. car := VerCar;
  537. If car = '' Then Exit;
  538. If Not (car in CAR_VAL_PALABRA) Then //primer caracter valido
  539. Exit; //no es identificador
  540. temp := temp + CogCar; //acumula
  541. //busca hasta encontrar fin de identificador
  542. While VerCar <> '' do begin
  543. car := VerCar;
  544. If car in CAR_VAL_PALABRA Then begin
  545. CogCar; //toma el caracter
  546. temp += car; //acumula
  547. end Else begin
  548. cogPalabra := temp; //copia el identificador
  549. Exit;
  550. End;
  551. end;
  552. //se llego al final del archivo
  553. cogPalabra := temp; //copia hasta el final
  554. End;
  555. function TPPro.CogElemento: String;
  556. {Toma un elemento de una cadena. El elemento puede ser un identificador,
  557. un símbolo o una frase. Los elementos se separan por caracteres "blancos".
  558. Por ejemplo, la cadena:
  559. casa 1 'nueva casa'
  560. Tiene 3 elementos: "casa", "1" y "nueva casa".}
  561. Var temp:String;
  562. car:char;
  563. begin
  564. CapBlancos; //quita blancos iniciales
  565. If cEnt.VerCar = '''' Then //Inicio de cadena
  566. Result := CogCadena
  567. Else begin
  568. temp := '';
  569. While cEnt.VerCar <> '' do begin
  570. car := cEnt.VerCar;
  571. If not (car in [' ',#9,FIN_LIN, FIN_CON]) Then begin
  572. cEnt.CogCar; //toma el caracter
  573. temp += car; //acumula
  574. end Else begin
  575. Result := temp; //copia el identificador
  576. Exit;
  577. End;
  578. end;
  579. //se llego al final del archivo
  580. Result := temp; //copia hasta el final
  581. End;
  582. End;
  583. function TPPro.CogNumero: Single;
  584. {Coge una cifra numerica, del contexto actual, desde la posicón actual.
  585. Primero elimina los blancos. Si no encuentra algún caracter numérico al inicio, o el
  586. signo menos, sale }
  587. begin
  588. CogNumero(Result);
  589. End;
  590. function TPPro.CogNumero(var n: Single): boolean;
  591. Var car:char;
  592. temp:String;
  593. begin
  594. Result := false ; //no hay numero
  595. CapBlancos;
  596. car := cEnt.VerCar;
  597. If Not (car in ['0'..'9','.','-']) Then //primer caracter no valido
  598. Exit; //no es numero
  599. if (car in ['.','-']) and not (cEnt.VerCarSig in ['0'..'9']) then
  600. Exit; //no es válido
  601. temp := cEnt.CogCar; //acumula primer dígito
  602. //busca hasta encontar fin de identificador
  603. While cEnt.VerCar in ['0'..'9','.'] do begin
  604. car := cEnt.CogCar; //toma el caracter
  605. temp += car; //acumula
  606. end;
  607. //se llego al final del número
  608. n := StrToFloat(temp); //copia hasta el final
  609. Result := true; //indica que hubo número
  610. end;
  611. function TPPro.CogCadena: String;
  612. begin
  613. CogCadena(Result);
  614. End;
  615. function TPPro.CogCadena(var s: string): boolean;
  616. {Coge una constante de tipo cadena (entre apóstrofos) desde la posicion
  617. donde se encuentra el archivo, hasta el delimitador o fin de línea.
  618. Si no encuentra una cadena, devuelve FALSE}
  619. Var car : char;
  620. begin
  621. PErr.IniError;
  622. Result := false; //no hay cadena
  623. CapBlancos; //quita blancos iniciales
  624. s := '';
  625. car := cEnt.VerCar;
  626. If car <> '''' Then //primer caracter no valido
  627. Exit; //no es constante cadena
  628. cEnt.CogCar; //toma el caracter
  629. Result := true; //indica que se encontró cadena
  630. //busca hasta encontar fin de identificador
  631. While not(cEnt.VerCar in [FIN_LIN, FIN_CON]) do begin
  632. car := cEnt.CogCar;
  633. If car <> '''' Then begin
  634. s += car; //acumula
  635. end Else begin
  636. Exit;
  637. End;
  638. end;
  639. //se llego al final del archivo
  640. PErr.GenError('No se encontro fin de cadena', PosAct);
  641. end;
  642. function TPPro.coger_ruta: String;
  643. //Coge una cadena que representa la ruta de un archivo (con o sin apóstrofos)
  644. //desde la posicion donde se encuentra el archivo
  645. Var temp:String;
  646. car:String;
  647. begin
  648. PErr.IniError;
  649. coger_ruta := ''; //no hay cadena
  650. CapBlancos; //quita blancos iniciales
  651. temp := '';
  652. car := VerCar;
  653. If car = '' Then Exit;
  654. If car = '''' Then begin //ruta en formato de cadena
  655. temp := CogCadena;
  656. If PErr.HayError Then Exit;
  657. coger_ruta := temp;
  658. Exit; //no es constante cadena
  659. end Else begin
  660. //busca hasta encontar blanco (espacio o salto de línea, o tab)
  661. While Not FinCont And Not (VerCar in [' ',#9,FIN_LIN]) do
  662. temp += CogCar; //acumula
  663. Result := temp; //copia
  664. //se llego al final del archivo
  665. // GenError 1, "No se encontro fin de cadena", ArcActual, filAct
  666. End;
  667. End;
  668. function TPPro.TipoSigToken: TtkTokenKind;
  669. //Identifica el token que inicia en la posición actual.
  670. begin
  671. case VerCar of
  672. '$','a'..'z','A'..'Z','_': Result := tkIdentifier;
  673. else
  674. Result := tkUnknown;
  675. end;
  676. end;
  677. function TPPro.VerSiEsComentario: Boolean;
  678. //devuelve verdad si la posicion actual del archivo de entrada corresponde
  679. //al inicio de un comentario. No Filtra blancos iniciales ni salta lineas
  680. var cad: string[2];
  681. begin
  682. VerSiEsComentario := False;
  683. cad := VerCarN(2);
  684. Result := (cad = '--') or (cad = '/*');
  685. End;
  686. function TPPro.CogerHastaFinLinea: String;
  687. //coge una cadena correspondiente a los caracteres desde el punto actual hasta el fin de la linea
  688. Var temp:String;
  689. begin
  690. temp := '';
  691. While Not cEnt.FinCont And (cEnt.VerCar <> FIN_LIN) do
  692. temp += cEnt.CogCar;
  693. cEnt.CogCar; //Coge el fin de línea
  694. //se llego al final del archivo o al fin de linea
  695. Result := temp; //copia hasta el final
  696. End;
  697. function TPPro.CogerHastaComent: String;
  698. //Coge texto hasta encontrar el inicio de un comentario o un salto de línea
  699. var linact : string;
  700. i,j, min: integer;
  701. begin
  702. linact := cEnt.lin[cEnt.fil-1]; //línea actual
  703. //busca posiicón de comentario
  704. min := length(linact)+1; //valor inicial
  705. i := Pos('--',linAct);
  706. if i<>0 then min := i; //primer valor
  707. j := Pos('/*',linAct);
  708. if j < cEnt.col then j := 0; //comentarios anteriores (/* ... */), se ignoran.
  709. if j<>0 then //hay otro
  710. if j < min then min := j; //compara valor
  711. //toma los caracteres necesarios
  712. Result := Copy(linAct,cEnt.col,min-cEnt.col); //copia hasta el final
  713. cEnt.col := min; //pone kasta posición leida
  714. if min = length(linact) + 1 then CogCar; //Coge el fin de línea
  715. end;
  716. function TPPro.CogerComent: boolean;
  717. {Coge un comantario, de tipo /* .. */. Debe llamarse cuando se ha detectado
  718. el inicio de este comentario. Puede coger varias líneas.}
  719. begin
  720. Result := false;
  721. while not FinCont do begin
  722. if cEnt.CogCar = '*' then begin
  723. //puede ser delimitador final
  724. if cEnt.VerCar = '/' then begin
  725. cEnt.CogCar; //toma el delimitador
  726. Result := true;
  727. exit; //sale
  728. end;
  729. end;
  730. end;
  731. end;
  732. function TPPro.CogerLista(lista: TStringList; delims: string): string;
  733. {Estrae una lista de elementos del contexto actual, hasta encontrar uno de los
  734. delimitadores indicados en "delims". Si termina por encontrar un delimitador,
  735. devuelve el delimitador encontrado (siempre en mayúscula). Los delimitadores
  736. deben indicarse separados por coma, sin esapcios entre ellos}
  737. var tmp: string;
  738. l_delims : TstringList;
  739. begin
  740. Result:='';
  741. l_delims := TStringList.Create; //crea lista
  742. l_delims.Delimiter:=',';
  743. l_delims.DelimitedText:=delims; //descompone lista
  744. { --VERSIÓN SIN COGER ELEMENTO
  745. tmp := VerElemento; //toma primero
  746. While Not FinCont do begin
  747. If l_delims.IndexOf(tmp) <> -1 Then //busca delimitador
  748. begin Result:= tmp; break end; //encontro delimitador, sale.
  749. lista.add(CogElemento); //agrega elemento
  750. tmp := VerElemento; //toma siguiente
  751. end;}
  752. repeat
  753. tmp := CogElemento; //toma siguiente
  754. if tmp = '' then break; //es fin de contexto, porque CogElemento toma cualquier cosa
  755. If l_delims.IndexOf(tmp) <> -1 Then begin //busca delimitador
  756. Result:= Upcase(tmp); break; //encontro delimitador, sale.
  757. end;
  758. lista.add(tmp); //agrega elemento
  759. until Cent.FinCont;
  760. //aquí puede haber llegado por fin de contexto o por haber encontrado
  761. //algún delimitador.
  762. l_delims.Free;
  763. end;
  764. function TPPro.VerHastaFinLinea: String;
  765. //Devuelve una cadena correspondiente a los caracteres desde el punto actual hasta el fin de
  766. //la linea. Empieza a buscar desde el principio.
  767. Var nfilTmp:LongInt;
  768. ncolTmp:Integer;
  769. begin
  770. nfilTmp := cEnt.fil;
  771. ncolTmp := cEnt.col;
  772. VerHastaFinLinea := CogerHastaFinLinea;
  773. cEnt.fil := nfilTmp; //devuelve el numero de linea inicial
  774. cEnt.col := ncolTmp;
  775. End;
  776. //********************************************************************************
  777. //Funciones para manejo de la salida
  778. //********************************************************************************
  779. procedure TPPro.NuevoContexSal;
  780. //Crea un nuevo contexto de salida y pone cursor al inicio.
  781. begin
  782. //Crea Contexto de salida
  783. cSal := TContexto.Create;
  784. ConsS.Add(cSal); //Registra Contexto
  785. cSal.FijCad(''); //Iniicia cadena y posiciona cursor al final
  786. end;
  787. procedure TPPro.QuitaContexSal;
  788. //Elimina el contexto de salida actual. Deja apuntando al anterior en la misma posición.
  789. begin
  790. if ConsS.Count = 0 then exit; //no sep uede quitar más
  791. ConsS.Delete(ConsS.Count-1);
  792. if ConsS.Count = 0 then
  793. cSal := nil
  794. else //apunta al último
  795. CSal := ConsS[ConsS.Count-1];
  796. end;
  797. procedure TPPro.PonCar(c: char);
  798. begin
  799. cSal.PonCar(c);
  800. end;
  801. procedure TPPro.Escribe(palabra: string);
  802. //Escribe un palabra en el archivo de salida. Este debe ser el único punto
  803. //de acceso al archivo de salida.
  804. begin
  805. cSal.PonCad(palabra);
  806. end;
  807. procedure TPPro.EscribeSalto;
  808. //Escribe un salto de línea en el archivo de salida.
  809. begin
  810. cSal.PonSalto;
  811. end;
  812. procedure TPPro.SacCar;
  813. //Quita un caracter del dispositivo de salida, borrando la información previamente escrita.
  814. begin
  815. cSal.SacCar;
  816. end;
  817. procedure TPPro.GenArchivo(ArcSal0: string);
  818. //Genera el archivo de salida
  819. begin
  820. if ArcSal0 = '' then exit; //protección
  821. cSal.lin.SaveToFile(ArcSal0);
  822. end;
  823. function TPPro.TextSalida: string;
  824. begin
  825. Result := cSal.lin.Text;
  826. end;
  827. function TPPro.cogOperador: String;
  828. {Coge un operador en la posición del contexto actual. Si no encuentra
  829. devuelve cadena vacía y no coge caracteres, salvo espacios iniciales.}
  830. begin
  831. cogOperador := '';
  832. CapBlancos; //quita blancos iniciales
  833. Case VerCar of //completa con operador de más caracteres
  834. '+': begin
  835. Result := CogCar;
  836. // If VerCar = '+' Then begin CogCar; Result := '++' end;
  837. // If VerCar = '=' Then begin CogCar; Result := '+=' end;
  838. end;
  839. '-': begin
  840. Result := CogCar;
  841. // If VerCar() = '-' Then begin CogCar; Result := '--' end;
  842. // If VerCar() = '=' Then begin CogCar; Result := '-=' end;
  843. end;
  844. '*': begin
  845. Result := CogCar;
  846. // If VerCar() = '=' Then begin CogCar; Result := '*=' end;
  847. end;
  848. '/': begin
  849. Result := CogCar;
  850. // If VerCar() = '=' Then begin CogCar; Result := '/=' end;
  851. end;
  852. // '=': begin
  853. // Result := CogCar;
  854. // If VerCar() = '=' Then begin CogCar; Result := '==' end;
  855. // If VerCar() = '<' Then begin CogCar; Result := '=<' end; //operador 'menor'
  856. // If VerCar() = '>' Then begin CogCar; Result := '=>' end; //operador 'mayor'
  857. // end;
  858. // '>': begin
  859. // Result := CogCar;
  860. // If VerCar() = '=' Then begin CogCar; Result := '>=' end;
  861. // If VerCar() = '>' Then begin CogCar; Result := '>>' end;
  862. // If VerCar() = '+' Then begin CogCar; Result := '>+' end;
  863. // If VerCar() = '-' Then begin CogCar; Result := '>-' end;
  864. // end;
  865. // '<': begin
  866. // Result := CogCar;
  867. // If VerCar() = '=' Then begin CogCar; Result := '<=' end;
  868. // If VerCar() = '>' Then begin CogCar; Result := '<>' end;
  869. // If VerCar() = '<' Then begin CogCar; Result := '<<' end;
  870. // end;
  871. // '|': begin
  872. // Result := CogCar;
  873. // If VerCar() = '|' Then begin CogCar; Result := '||' end; //OR
  874. // If VerCar() = '!' Then begin CogCar; Result := '|!' end; //XOR
  875. // end;
  876. // '~': begin //operador LIKE
  877. // Result := CogCar;
  878. // end;
  879. // '&': begin
  880. // Result := CogCar;
  881. // If VerCar = '&' Then begin CogCar; Result := '&&' end; //AND
  882. // end;
  883. End;
  884. End;
  885. function TPPro.jerOp(oper: String): Integer;
  886. //Devuelve la jerarquía de un operador ver documentación técnica.
  887. begin
  888. Case oper of
  889. // '>>', '<<', '>+', '>-': jerOp = 1: Exit Function
  890. // '=': jerOp := 2;
  891. // '&&', '||', '!', '|!': jerOp := 3;
  892. // '==', '<>', '>', '>=', '<', '<=', '~': jerOp := 4;
  893. '+', '-'{, '|', '&'}: jerOp := 5;
  894. '*', '/'{, '\', '%'}: jerOp := 6;
  895. // '=<', '=>': jerOp := 7;
  896. // '^', '++', '--', '+=', '-=', '*=', '/=': jerOp := 8;
  897. Else jerOp := 0;
  898. End;
  899. End;
  900. function TPPro.Evaluar(Op1: Texpre; opr: String; Op2: Texpre): Texpre;
  901. //Devuelve el resultado y tipo de una operación
  902. begin
  903. PErr.IniError;
  904. Evaluar.cat := COP_EXPRESION; //ahora es expresión por defecto
  905. Case opr of
  906. '': begin //Sin operador. Y se supone sin Op2
  907. //no hay nada que hacer, ya está en la pila
  908. Evaluar := Op1;
  909. end;
  910. { '=': begin //Asignación
  911. If Op1.cat = COP_DEFINIC Then begin //Asignación a una variable
  912. // Evaluar.val := Op2.val;
  913. // Evaluar.tip := Op2.tip;
  914. Op1 := Op2;
  915. tDefi Op1.def:=;
  916. Evaluar:= Op1
  917. end Else
  918. Perr.GenError('Sólo se puede asignar valor a una variable', PosAct);
  919. end;}
  920. '+': begin
  921. Evaluar.valNum := Op1.valNum + Op2.valNum; //Fuerza a Evaluar.tip := TIP_NUM
  922. end;
  923. '-': begin
  924. Evaluar.valNum := Op1.valNum - Op2.valNum;
  925. end;
  926. '*': begin
  927. Evaluar.valNum := Op1.valNum * Op2.valNum;
  928. end;
  929. '/': begin
  930. If Op2.valNum = 0 Then
  931. Perr.GenError('No se puede dividir por cero.', PosAct)
  932. Else begin //error
  933. Evaluar.valNum := Op1.valNum / Op2.valNum;
  934. End;
  935. end;
  936. { '\': begin
  937. If val(Op2.val) = 0 Then
  938. Perr.GenError('No se puede dividir por cero.', PosAct);
  939. Else begin //error
  940. Evaluar.val := val(Op1.val) \ val(Op2.val);
  941. Evaluar.tip := TIP_NUM;
  942. End;
  943. end;
  944. '%': begin
  945. If val(Op2.val) = 0 Then
  946. Perr.GenError('No se puede dividir por cero.', PosAct);
  947. Else begin //error
  948. Evaluar.val := val(Op1.val) Mod val(Op2.val);
  949. Evaluar.tip := TIP_NUM;
  950. End;
  951. end;
  952. '^': begin
  953. If val(Op2.val) = 0 And val(Op2.val) = 0 Then
  954. Perr.GenError('No se puede Evaluar 0^0', PosAct);
  955. Else begin //error
  956. Evaluar.val := val(Op1.val) ^ val(Op2.val);
  957. Evaluar.tip := TIP_NUM;
  958. End;
  959. end;
  960. '++': begin //mono-operando, sólo Op1
  961. Op1.val := val(Op1.val) + 1 //incrementa
  962. Evaluar.val := Op1.val;
  963. Evaluar.tip := TIP_NUM;
  964. end;
  965. '--': begin //mono-operando
  966. Op1.val := val(Op1.val) - 1 //decrementa
  967. Evaluar.val := Op1.val;
  968. Evaluar.tip := TIP_NUM;
  969. //operadores de comparación
  970. end;
  971. '==': begin
  972. If Op1.val := Op2.val Then
  973. Evaluar.val := 1
  974. Else //error
  975. Evaluar.val := 0
  976. Evaluar.tip := TIP_NUM
  977. end;
  978. '<>': begin
  979. If Op1.val <> Op2.val Then
  980. Evaluar.val := 1
  981. Else //error
  982. Evaluar.val := 0
  983. Evaluar.tip := TIP_NUM
  984. end;
  985. '>': begin
  986. If Op1.val > Op2.val Then
  987. Evaluar.val := 1
  988. Else //error
  989. Evaluar.val := 0
  990. Evaluar.tip := TIP_NUM
  991. end;
  992. '<': begin
  993. If Op1.val < Op2.val Then
  994. Evaluar.val := 1
  995. Else //error
  996. Evaluar.val := 0
  997. Evaluar.tip := TIP_NUM
  998. end;
  999. '>=': begin
  1000. If Op1.val >= Op2.val Then
  1001. Evaluar.val := 1
  1002. Else //error
  1003. Evaluar.val := 0
  1004. Evaluar.tip := TIP_NUM
  1005. end;
  1006. '<=': begin
  1007. If Op1.val <= Op2.val Then
  1008. Evaluar.val := 1
  1009. Else //error
  1010. Evaluar.val := 0
  1011. Evaluar.tip := TIP_NUM
  1012. end;
  1013. '|': begin //concatenación de cadenas
  1014. Evaluar.val := Op1.val & Op2.val
  1015. Evaluar.tip := TIP_CAD
  1016. end;
  1017. '~': begin //comparación de cadenas
  1018. If (Op1.val Like Op2.val) Then
  1019. Evaluar.val := 1
  1020. Else //no cuadra
  1021. Evaluar.val := 0
  1022. Evaluar.tip := TIP_NUM
  1023. end;
  1024. '&&': begin //And lógico
  1025. If (val(Op1.val) = 1 And val(Op2.val) = 1) Then
  1026. Evaluar.val := 1
  1027. Else //no cuadra
  1028. Evaluar.val := 0
  1029. Evaluar.tip := TIP_NUM
  1030. end;
  1031. '||': begin
  1032. If (val(Op1.val) = 0 And val(Op2.val) = 0) Then
  1033. Evaluar.val := 0
  1034. Else //no cuadra
  1035. Evaluar.val := 1
  1036. Evaluar.tip := TIP_NUM
  1037. end;
  1038. '!': begin
  1039. If val(Op1.val) = 1 Then
  1040. Evaluar.val := 0
  1041. Else //no cuadra
  1042. Evaluar.val := 1
  1043. Evaluar.tip := TIP_NUM
  1044. end;}
  1045. Else begin
  1046. Perr.GenError('No se reconoce operador: ' + opr, PosAct);
  1047. Exit;
  1048. End;
  1049. end;
  1050. //Completa campos de evaluar
  1051. Evaluar.txt := Op1.txt + opr + Op2.txt; //texto de la expresión
  1052. // Evaluar.uop := opr; //última operación ejecutada
  1053. End;
  1054. { TPError }
  1055. procedure TPError.IniError;
  1056. begin
  1057. numER := 0;
  1058. cadError := '';
  1059. arcER := '';
  1060. fil := 0;
  1061. col := 0;
  1062. end;
  1063. procedure TPError.GenError(num: Integer; msje: String; archivo: String;
  1064. nlin: integer = 0);
  1065. //Genera un error
  1066. begin
  1067. numER := num;
  1068. cadError := msje;
  1069. arcER := archivo;
  1070. fil := nlin;
  1071. end;
  1072. procedure TPError.GenError(msje: String; posCon: TPosCont);
  1073. //Genera un error en la posición indicada
  1074. begin
  1075. numER := 1;
  1076. cadError := msje;
  1077. arcER := posCon.arc;
  1078. fil := posCon.fil;
  1079. col := posCon.col;
  1080. end;
  1081. function TPError.GenTxtError: string;
  1082. //Genera una cadena con el mensaje de error de acuerdo al nivel de detalle que tenga.
  1083. begin
  1084. Result :=cadError;
  1085. If arcER <> '' Then begin //agrega información de archivo
  1086. Result += LineEnding + arcER;
  1087. end;
  1088. If fil <> 0 Then begin //Hay número de línea
  1089. // Result := Pchar('[' + arcER + ']: ' + cadError + ' Línea: ' + IntToStr(fil);
  1090. Result += LineEnding + '(' +IntToStr(fil) + ',' + IntToStr(col) + ') ';
  1091. end;
  1092. end;
  1093. {procedure TPError.MosError;
  1094. //Muestra un mensaje de error
  1095. begin
  1096. writeln(TxtError); No debe ser dependiente del tipo de Aplicación
  1097. end;}
  1098. function TPError.ArcError: string;
  1099. //Devuelve el nombre del archivo de error
  1100. begin
  1101. ArcError := arcER;
  1102. end;
  1103. function TPError.nLinError: longint;
  1104. //Devuelve el número de línea del error
  1105. begin
  1106. nLinError := fil;
  1107. end;
  1108. function TPError.nColError: longint;
  1109. //Devuelve el número de línea del error
  1110. begin
  1111. nColError := col;
  1112. end;
  1113. function TPError.HayError: boolean;
  1114. begin
  1115. HayError := numER <> 0;
  1116. end;
  1117. { TContexto }
  1118. //********************************************************************************
  1119. //Funciones Básicas para administración de los Contextos
  1120. //********************************************************************************
  1121. constructor TContexto.Create;
  1122. begin
  1123. inherited; //solo se pone por seguridad, ya que no es necesario.
  1124. lin := TStringList.Create; //crea lista de cadenas para almacenar el texto
  1125. nlin := 0;
  1126. CurPosFin; //inicia fil y col
  1127. end;
  1128. destructor TContexto.Destroy;
  1129. begin
  1130. lin.Free; //libera lista
  1131. inherited Destroy;
  1132. end;
  1133. function TContexto.IniCont: Boolean;
  1134. //Devuelve verdadero si se está al inicio del Contexto (fila 1, columna 1)
  1135. begin
  1136. Result := (fil = 1) And (col = 1);
  1137. end;
  1138. function TContexto.FinCont: Boolean;
  1139. //Devuelve verdadero si se ha pasado del final del Contexto actual
  1140. begin
  1141. //Protección a Contexto vacío
  1142. If nlin = 0 Then begin
  1143. Result := True;
  1144. Exit;
  1145. End;
  1146. //Verifica optimizando verificando primero la condición más probable
  1147. If fil < nlin Then
  1148. Result := False
  1149. Else If fil > nlin Then
  1150. Result := True
  1151. Else If fil = nlin Then begin
  1152. //Verifica si estamos en la línea final.
  1153. //OJO, en la línea final no existe un salto de línea adicional
  1154. If col >= Length(lin[fil-1]) + 1 Then
  1155. Result := True
  1156. Else
  1157. Result := False
  1158. End;
  1159. end;
  1160. function TContexto.VerCar: Char;
  1161. //Devuelve el caracter actual
  1162. begin
  1163. If FinCont Then Exit(FIN_CON);
  1164. If col = Length(lin[fil-1]) + 1 Then begin
  1165. //Se está al fin de la línea. Se considera que cada línea
  1166. //tiene un salto de línea al final, excepto la última línea.
  1167. //En este caso siempre se devuelve FIN_LIN
  1168. Result := FIN_LIN
  1169. end Else //No se está al fin de la línea
  1170. Result := lin[fil-1][col];
  1171. end;
  1172. function TContexto.CogCar: Char;
  1173. //Lee un caracter del contexto y avanza el cursor una posición.
  1174. begin
  1175. If FinCont Then Exit(FIN_CON);
  1176. If col >= Length(lin[fil-1]) + 1 Then begin
  1177. //Se está al fin de la línea. Trabaja igual que VerCar().
  1178. Result := FIN_LIN;
  1179. col := 1;
  1180. fil := fil + 1; //Pasa a siguiente fila, puede ser que se
  1181. //haya pasado la cantidad de líneas disponibles
  1182. end Else begin //No se está al fin de la línea
  1183. Result := lin[fil-1][col];
  1184. inc(col);
  1185. End;
  1186. end;
  1187. function TContexto.VerCarAnt: Char;
  1188. //echa un vistazo al caracter anterior del Contexto
  1189. //Si no hay caracter anterior, devuelve cadena vacía
  1190. Var linact:String;
  1191. begin
  1192. Result := #0;
  1193. If IniCont Then Exit; //No hay caracter anterior
  1194. linact := lin[fil-1]; //línea actual
  1195. If col = 1 Then
  1196. //Está al inicio de una línea
  1197. Result := FIN_LIN //devuelve el salto anterior
  1198. Else
  1199. Result := linact[col-1];
  1200. end;
  1201. function TContexto.VerCarSig: Char;
  1202. //Devuelve el catacter siguiente al actual. OJO: Solo mira la línea actual.
  1203. begin
  1204. If FinCont Then Exit(FIN_CON);
  1205. If col >= Length(lin[fil-1]) Then begin
  1206. Result := FIN_LIN
  1207. end Else //No se está al fin de la línea
  1208. Result := lin[fil-1][col+1];
  1209. end;
  1210. function TContexto.CapBlancos: Boolean;
  1211. //Coge los blancos iniciales del contexto de entrada.
  1212. //Si no encuentra algun blanco al inicio, devuelve falso
  1213. begin
  1214. Result := False;
  1215. if not (VerCar in [' ', FIN_LIN, #9]) then exit; //no hay blancos
  1216. repeat
  1217. CogCar
  1218. until FinCont or not (VerCar in [' ', FIN_LIN, #9]);
  1219. end;
  1220. procedure TContexto.CurPosIni;
  1221. //Mueve la posición al inicio del contenido.
  1222. begin
  1223. if lin.Count = 0 then begin
  1224. fil := 0; col := 0;
  1225. end else
  1226. begin
  1227. fil := 1;
  1228. col := 1; //posiciona al inicio
  1229. end;
  1230. end;
  1231. procedure TContexto.CurPosFin;
  1232. //Mueve la posición al final del contenido.
  1233. begin
  1234. if lin.Count = 0 then begin
  1235. fil := 0; col := 0;
  1236. end else
  1237. begin
  1238. fil := lin.Count;
  1239. col := length(lin[fil-1])+1; //posiciona al final
  1240. end;
  1241. end;
  1242. procedure TContexto.PonSalto;
  1243. //Escribe un salto de línea en el contexto
  1244. begin
  1245. lin.Add('');
  1246. fil := lin.Count; //actualiza filas
  1247. col := 1; //posiciona en primera columna
  1248. end;
  1249. procedure TContexto.SacLinea;
  1250. //Saca la última línea del contexto. Debe haber por lo menos una línea
  1251. begin
  1252. if lin.Count = 0 then exit;
  1253. lin.Delete(lin.Count-1); //elimina última línea
  1254. CurPosFin; //actualiza posición de cursor
  1255. end;
  1256. procedure TContexto.PonCar(c: char);
  1257. //Escribe un caracter en el contexto. Debe haber por lo menos una línea
  1258. begin
  1259. if lin.Count = 0 then exit; //sin datos
  1260. if c = FIN_LIN then //caracter de salto de línea
  1261. PonSalto
  1262. else begin //caracter normal
  1263. lin[lin.Count-1] := lin[lin.Count-1] + c; //agrega a línea actual
  1264. inc(col); //actualiza columna
  1265. end;
  1266. end;
  1267. procedure TContexto.PonCad(s: String);
  1268. //Escribe una cadena (sin saltos) en el contexto. Debe haber por lo menos una línea
  1269. begin
  1270. if lin.Count = 0 then exit; //sin datos
  1271. lin[lin.Count-1] := lin[lin.Count-1] + s; //agrega a línea actual
  1272. col += length(s); //actualiza columna
  1273. end;
  1274. procedure TContexto.SacCar;
  1275. //Quita un caracter del contexto
  1276. var n:integer;
  1277. begin
  1278. n := lin.Count;
  1279. if n = 0 then exit; //sin datos
  1280. if (n = 1) and (length(lin[0])=0) then exit; //sin datos
  1281. //hay datos
  1282. if col = 1 then //al inicio de línea
  1283. SacLinea
  1284. else begin
  1285. lin[n-1] := copy(lin[n-1],1,col-2); //recorta
  1286. CurPosFin; //actualiza posición de cursor
  1287. end;
  1288. end;
  1289. function TContexto.LeeCad: string;
  1290. //Devuelve el contenido del contexto en una cadena.
  1291. begin
  1292. Result := lin.text;
  1293. end;
  1294. procedure TContexto.FijCad(cad: string);
  1295. //Fija el contenido del contexto con una cadena.
  1296. begin
  1297. tip := TC_TXT; //indica que contenido es Texto
  1298. if cad='' then begin
  1299. //cadena vacía, crea una línea vacía
  1300. lin.Clear;
  1301. lin.Add('');
  1302. nlin := 1; //actualiza número de líneas
  1303. end else begin
  1304. lin.Text := cad;
  1305. nlin := lin.Count; //actualiza número de líneas
  1306. end;
  1307. CurPosFin; //actualiza posición de cursor
  1308. arc := ''; //No se incluye información de archivo
  1309. end;
  1310. procedure TContexto.FijArc(arc0: string);
  1311. //Fija el contenido del contexto con un archivo
  1312. begin
  1313. tip := TC_TXT; //indica que contenido es Texto
  1314. lin.LoadFromFile(arc0);
  1315. nlin := lin.Count; //actualiza número de líneas
  1316. CurPosFin; //actualiza posición de cursor
  1317. arc := arc0; //No se incluye información de archivo
  1318. end;
  1319. initialization
  1320. PPro.Create;
  1321. finalization
  1322. PPro.Destroy;
  1323. end.