uPreProces.pas 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. {
  2. uPreProces
  3. Modificado por Tito Hinostroza 03/11/2014
  4. Unidad que define la sintaxis del PreSQL 2.0. Adaptado de la versión 1.3 de VB.
  5. Se define esta unidad para implementar el procesamiento de un texto o archivo.
  6. No se incluyen mensajes de tipo writeln(), o ShowMessage(), para evitar hacer a
  7. la unidad dependiente del tipo de aplicación.
  8. }
  9. unit uPreProces; {$mode objfpc}{$H+}
  10. interface
  11. uses
  12. Classes, SysUtils, Fgl, FileUtil, DateUtils, uPreBasicos;
  13. procedure PreProcesar(arc: String; txt: String; var cadcon0: string);
  14. implementation
  15. //---------Manejo de definiciones------------
  16. Const MAX_DEFINICIONES = 500;
  17. Const MAX_INCLUSIONES = 50;
  18. //Tipos de definiciones
  19. Const TD_CON = 0; //Definición de contexto
  20. Const TD_DIR = 1; //Definición directaD
  21. Type
  22. { Tdefinicion }
  23. Tdefinicion = class //estructura de definicion
  24. //Notar que esta clase accede a los objetos globales PProc y PErr
  25. nom: String; //nombre de la definicion
  26. tip: Integer; //Tipo de definición
  27. con: TPosCont; //Ubicación donde está el texto de la definicion
  28. txt: String; //Texto de la definición (Solo las de Tipo directo)
  29. procedure Expandir; //espande la definición y escribe en la salida
  30. function ValTxt: string; //devuelve la defición expandida
  31. procedure FijTxt(t: string); //fija un valor de texto a la definición
  32. procedure LeeElementos(elem: TStringList); //lee definición como lista
  33. End;
  34. Tinclusion = class
  35. arc: string; //archivo incluido
  36. pad: string; //archivo padre
  37. end;
  38. //Define una lista de definiciones
  39. TListaDef = specialize TFPGObjectList<Tdefinicion>;
  40. TListaInc = specialize TFPGObjectList<Tinclusion>;
  41. //----------Manejo de inclusiones-------------
  42. var
  43. cad_con: string; //variable interna para cadena de conexión.
  44. definiciones: TListaDef; //Lista de definiciones
  45. inclusiones: TListaInc; //Lista de inclusiones
  46. arcEnt : string; //archivo de entrada
  47. procedure decodificar_PARA; forward;
  48. procedure preProcesarCad(txt: String; archivo: String); forward;
  49. procedure preProcesarArc(archivo: String); forward;
  50. procedure decodificar_INCLUIR(IncluirMult: Boolean = False); forward;
  51. Function CogExpresion(jerar: Integer): Texpre; forward;
  52. Function definido(ident: String): Tdefinicion; forward;
  53. Function preProcFuncion(identif: String): Boolean; forward;
  54. /////////////////////// Funciones para evaluación de expresiones ///////////////////////
  55. Function CogOperando: Texpre;
  56. //Coge un operando en la posición actual del contenido
  57. var c : String;
  58. cad : String;
  59. num : single;
  60. exp : Texpre;
  61. def : Tdefinicion;
  62. begin
  63. PPro.CapBlancos; //quita blancos iniciales
  64. c := UpCase(PPro.VerCar);
  65. {If EsFuncion() Then //Sólo funciones predefinidas
  66. CogOperando := CogFuncion;
  67. Else} If PPro.CogNumero(num) then begin
  68. CogOperando.txt := '#'; //indica número
  69. CogOperando.valNum := num; //fija tipo a número
  70. CogOperando.cat := COP_CONST;
  71. end Else If PPro.CogCadena(cad) Then begin //Constante cadena
  72. CogOperando.txt := '?'; //indica cadena
  73. CogOperando.valTxt := cad; //fija tipo a número
  74. CogOperando.cat := COP_CONST;
  75. end Else If c = '(' Then begin
  76. PPro.CogCar; //coge paréntesis
  77. exp := CogExpresion(0);
  78. if PErr.HayError then exit;
  79. CogOperando := exp;
  80. If PPro.Capturar(')') Then begin
  81. Exit;
  82. end Else begin
  83. PErr.GenError('Error en expresión. Se esperaba ")"', PPro.PosAct);
  84. Exit; //error
  85. end;
  86. end else If PPro.CogIdentificador(cad) Then begin
  87. //puede ser definición o identificador desconocido
  88. def := definido(cad);
  89. if def = nil then begin
  90. PErr.GenError('Identificador desconocido: ' + cad, PPro.PosAct);
  91. Exit;
  92. end;
  93. //es definición, se considera como una variable
  94. CogOperando.txt := 'd'; //indica definición
  95. CogOperando.valTxt := def.ValTxt; //expande directamente
  96. // CogOperando.def := def; //guarda la referencia a la definición
  97. CogOperando.cat := COP_DEFINIC;
  98. end Else
  99. Exit; //no devuelve nada
  100. End;
  101. Function CogExpresion(jerar: Integer): Texpre;
  102. //Toma una expresión completa, en la posición actual del contenido
  103. var Op1, Op2 : Texpre;
  104. opr, opr2 : String;
  105. jerOpr, jerOpr2: Integer;
  106. pos1, pos2 : TPosCont;
  107. begin
  108. PPro.CapBlancos; //quita blancos iniciales
  109. Op1 := CogOperando; //error
  110. If Op1.txt = '' Then
  111. Exit;
  112. opr := PPro.cogOperador;
  113. If opr = '' Then begin
  114. CogExpresion := Op1;
  115. Exit
  116. End;
  117. jerOpr := PPro.jerOp(opr); //Hay operador, tomar su jerarquía
  118. //-------------------------- ¿Delimitada por jerarquía? ---------------------
  119. If jerOpr <= jerar Then begin //es menor que la que sigue, expres.
  120. CogExpresion := Op1; //solo devuelve el único operando que leyó
  121. Exit;
  122. End;
  123. While opr <> '' do begin
  124. pos1 := PPro.PosAct; //Guarda por si lo necesita
  125. Op2 := CogOperando;
  126. If Op2.txt = '' Then begin //error
  127. PErr.GenError('Error en expresión. Se esperaba operando.', PPro.PosAct);
  128. Exit;
  129. end;
  130. pos2 := PPro.PosAct; //Guarda por si lo necesita
  131. opr2 := PPro.cogOperador;
  132. If opr2 <> '' Then begin //Hay otro operador
  133. jerOpr2 := PPro.jerOp(opr2);
  134. //¿Delimitado por jerarquía de operador?
  135. If jerOpr2 <= jerar Then begin //sigue uno de menor jerarquía, hay que salir
  136. PPro.PosAct := pos2; //antes de coger el operador
  137. CogExpresion := PPro.Evaluar(Op1, opr, Op2);
  138. Exit;
  139. End;
  140. If jerOpr2 > jerOpr Then begin //y es de mayor jerarquía, retrocede
  141. PPro.PosAct := pos1; //retrocede
  142. Op2 := CogExpresion(jerOpr); //evalua primero
  143. opr2 := PPro.cogOperador; //actualiza el siguiente operador
  144. End;
  145. End;
  146. Op1 := PPro.Evaluar(Op1, opr, Op2); //evalua resultado
  147. if PErr.HayError then exit;
  148. opr := opr2;
  149. jerOpr := PPro.jerOp(opr); //actualiza operador anterior
  150. end;
  151. CogExpresion := Op1;
  152. CogExpresion.cat := COP_EXPRESION;
  153. End;
  154. Function incluido(arc0: String): Tinclusion;
  155. //Devuelve la referencia a una inclusión. Si no esta incluido devuelve NIL.
  156. var s: Tinclusion;
  157. begin
  158. Result := nil; //valor por defecto
  159. For s in inclusiones do
  160. If UpCase(arc0) = s.arc Then begin //encontro
  161. Result := s;
  162. Exit;
  163. End;
  164. End;
  165. Function definido(ident: String): Tdefinicion;
  166. //devuelve la referencia a una definición. Si no esta definido devuelve NIL.
  167. var s: Tdefinicion;
  168. begin
  169. Result := nil; //valor por defecto
  170. For s in definiciones do
  171. If UpCase(ident) = s.nom Then begin //encontró
  172. Result := s;
  173. Exit;
  174. End;
  175. End;
  176. //************************************************************************************
  177. //**************************** MANEJO DE DEFINICIONES ********************************
  178. Function CreaDefinicionCon(nom: String; def: Tdefinicion = nil): Tdefinicion;
  179. //Ceea la nueva definición de contexto. El contenido debe leerse luego.
  180. //Si se especifica el índice se sobreescriben los datos.
  181. //Devuelve la definición creada.
  182. begin
  183. If def = nil Then begin //Se debe crear nueva definición
  184. If definiciones.Count >= MAX_DEFINICIONES Then begin
  185. PErr.GenError('Demasiadas definiciones.', PPro.PosAct);
  186. Exit;
  187. End;
  188. def := Tdefinicion.Create; //crea una nueva
  189. definiciones.Add(def); //la agrega a la lista
  190. End;
  191. //Se actualizan los datos
  192. def.nom := UpCase(nom); //guarda mayuscula
  193. def.tip := TD_CON ; //de tipo contexto
  194. def.txt := '';
  195. //Se guarda la posición donde empieza el cuerpo, tiene que ser después de la palabra COMO
  196. def.con := PPro.PosAct;
  197. Result := def;
  198. End;
  199. Function CreaDefinicionDir(nom: String; txt: String; def: Tdefinicion = nil): Tdefinicion;
  200. {Crea una definición directa. Si se especifica "def", se sobreescriben los datos
  201. de la definición. Si no se especifica se genera una definición nueva.
  202. Devuelve la definición directa creada.}
  203. begin
  204. If def = nil Then begin //Se debe crear nueva definición
  205. If definiciones.Count >= MAX_DEFINICIONES Then begin
  206. PErr.GenError('Demasiadas definiciones.', PPro.PosAct);
  207. Exit;
  208. End;
  209. def := Tdefinicion.Create; //crea una nueva
  210. definiciones.Add(def); //la agrega a la lista
  211. End;
  212. //Se actualizan los datos
  213. def.nom := UpCase(nom); //guarda mayuscula
  214. def.tip := TD_DIR ; //de tipo directo
  215. def.txt := txt;
  216. //Se guarda la posición donde empieza el cuerpo, tiene que ser después de la palabra IGUAL
  217. def.con := PPro.PosAct;
  218. Result := def;
  219. End;
  220. procedure EliminaDefinicion(ind: Tdefinicion);
  221. //Elimina una definición de la memoria. Se le debe proporcionar la referencia.
  222. begin
  223. If ind = nil Then Exit;
  224. definiciones.Remove(ind);
  225. End;
  226. procedure ProcCaracter(escribir: boolean = true);
  227. //Procesa un caracter del contexto de entrada.
  228. //Devuelve el caracter procesado.
  229. var uc: char;
  230. com: string[2];
  231. begin
  232. com := PPro.VerCarN(2);
  233. If com = '--' Then begin //es comentario de línea
  234. PPro.CogerHastaFinLinea;
  235. if escribir then PPro.EscribeSalto; //Escribe el salto quitado
  236. end Else if com = '/*' then begin //comentario de bloque
  237. PPro.CogerComent; //toma todo el comentario
  238. end Else begin
  239. uc := PPro.CogCar; //último caracter
  240. if escribir then PPro.PonCar(uc); //escribe siguiente caracter, si no hay error
  241. End;
  242. End;
  243. function ExpandirDefinido(nom: string): boolean;
  244. {Verifica si el identificador es una definición y de ser así lo expande y devuelve
  245. TRUE. De otra forma devuelve FALSE.}
  246. var def: Tdefinicion; //numero de definicion
  247. begin
  248. def := definido(nom);
  249. If def = nil Then begin
  250. Result := false; //no lo encuentra, devuelve falso
  251. end else begin //lo expande
  252. def.Expandir; //si hay errores se devuelven
  253. Result := true;
  254. End;
  255. End;
  256. procedure BuscaFINDEFINIR(posDef: TPosCont; nomDef: string);
  257. {Busca el delimitador FINDEFINIR en el contexto actual. Termina al encontrar el
  258. delimitador, o al encontrar algún error}
  259. var
  260. idenM: String;
  261. begin
  262. nomDef := UpCase(nomDef); //pasa a mayúscula
  263. //busca final de bloque $DEFINIR o $REDEF, sin escribir en salida.
  264. While Not PPro.FinCont do begin
  265. If PPro.CogIdentificador(idenM) Then begin
  266. If idenM = nomDef Then begin //verificación de llamada a la definiicón
  267. PErr.GenError('Llamada recursiva a "' + nomDef + '" en definición.', PPro.PosAct);
  268. Exit;
  269. End else If idenM = 'FINDEFINIR' Then begin
  270. PPro.CogIdentificador; //coge el "FINDEFINIR"
  271. PPro.CapBlancos; //quita blancos hasta siguiente identificador
  272. exit;
  273. end else If idenM = '$DEFINIR' Then begin //encontró otro definir
  274. PErr.GenError('Se esperaba "FINDEFINIR" de definición. ', posDef);
  275. Exit;
  276. end else If idenM = '$REDEF' Then begin //encontró otro definir
  277. PErr.GenError('Se esperaba "FINDEFINIR" de definición. ', posDef);
  278. Exit;
  279. End;
  280. //hay identificador pero no es reconocido. Lo ignora.
  281. end Else begin
  282. ProcCaracter(false); //va leyendo sin escribir
  283. end;
  284. end;
  285. //se ha llegado al fin de archivo, sin encontrar delimitador
  286. PErr.GenError('Inesperado fin de archivo. No se encontro "FINDEFINIR" de definición. ', posDef);
  287. end;
  288. procedure decodificar_DEFINIR;
  289. //Decodifica la instruccion $DEFINIR var COMO <bloque> FINDEFINIR
  290. var defi : String;
  291. temp : String;
  292. posDef: TPosCont; //posición temporal del contexto
  293. begin
  294. PErr.IniError;
  295. PPro.CapBlancos; //coge espacios después de "$DEFINIR"
  296. posDef := PPro.PosAct; //guarda posición
  297. defi := PPro.CogIdentificador; //coge nombre de la variable
  298. If defi = '' Then begin
  299. PErr.GenError('Se esperaba identificador después de $DEFINIR', PPro.PosAct);
  300. Exit;
  301. end;
  302. If definido(defi) <> nil Then begin //ya esta definida esa variable
  303. PErr.GenError('Ya esta definido el identificador ' + defi, PPro.PosAct);
  304. Exit;
  305. End;
  306. PPro.CapBlancos; //quita blancos iniciales
  307. If PPro.VerCar = '=' Then begin //Definición directa
  308. PPro.CogCar; //coge el "="
  309. // If UpCase(VerIdentificador) = '$CONSULTAR' Then begin
  310. // temp := decodificar_CONSULTAR(True);
  311. // If HayError Then Exit;
  312. // CreaDefinicionDir(UpCase(defi), temp);
  313. // end Else begin //Definición directa normal
  314. temp := PPro.CogerHastaComent;
  315. CreaDefinicionDir(defi, temp);
  316. // End;
  317. Exit;
  318. end Else If PPro.VerIdentifM = 'COMO' Then
  319. PPro.CogIdentificador
  320. Else begin
  321. PErr.GenError('Se esperaba "COMO" o "=" después de ' + defi, PPro.PosAct);
  322. Exit;
  323. End;
  324. //Crea la nueva definición y empieza lectura de contenido
  325. CreaDefinicionCon(defi);
  326. If PErr.HayError Then Exit;
  327. BuscaFINDEFINIR(posDef, defi); //Actualiza Error
  328. End;
  329. procedure decodificar_REDEF;
  330. //Decodifica la instruccion $REDEF var COMO <bloque> FINDEFINIR
  331. var defi : String; def: Tdefinicion;
  332. temp : String;
  333. posDef: TPosCont; //posición temporal del contexto
  334. begin
  335. PErr.IniError;
  336. PPro.CapBlancos; //coge espacios después de "$DEFINIR"
  337. posDef := PPro.PosAct; //guarda posición
  338. defi := PPro.CogIdentificador; //coge nombre de la variable
  339. If defi = '' Then begin
  340. PErr.GenError('Se esperaba identificador después de $REDEF', PPro.PosAct);
  341. Exit;
  342. end;
  343. def := definido(defi); //toma definición
  344. PPro.CapBlancos; //quita blancos iniciales
  345. If PPro.VerCar = '=' Then begin //Definición directa
  346. PPro.CogCar; //coge el "="{ TODO : No se guarda información del archivo donde se lee esta definición }
  347. // If UpCase(VerIdentificador) = '$CONSULTAR' Then begin
  348. // temp := decodificar_CONSULTAR(True);
  349. // If HayError Then Exit;
  350. // CreaDefinicionDir(UpCase(defi), temp);
  351. // end Else begin //Definición directa normal
  352. temp := PPro.CogerHastaComent;
  353. CreaDefinicionDir(defi, temp, def);
  354. // End;
  355. Exit;
  356. end Else If PPro.VerIdentifM = 'COMO' Then
  357. PPro.CogIdentificador
  358. Else begin
  359. PErr.GenError('Se esperaba "COMO" o "=" después de ' + defi, PPro.PosAct);
  360. Exit;
  361. End;
  362. //Crea o actualiza la definición y empieza lectura de contenido
  363. CreaDefinicionCon(defi, def);
  364. If PErr.HayError Then Exit;
  365. BuscaFINDEFINIR(posDef, defi); //Actualiza Error
  366. End;
  367. function procesarHastaDelim(delims: String): string;
  368. {Procesa el contexto actual hasta encontrar uno de los delimitadores, el fin del contexto
  369. o se genere algún error. Si termina por encontrar alguno de los delimitadores, coge el
  370. identificador y devuelve el delimitador encontrado (en mayúscula). La lista de
  371. delimitadores se debe dar separada por comas. La comparación con los identificadores
  372. se hace ignorando la caja.}
  373. var l_delims : TstringList;
  374. iden, idenM: String;
  375. uc : char; //último caracter
  376. begin
  377. Result := ''; //inicia
  378. l_delims := TStringList.Create; //crea lista
  379. //convierete lista de cadena en TSTringList
  380. l_delims.Delimiter:=',';
  381. l_delims.DelimitedText:=delims;
  382. //explora el contexto
  383. While Not PPRo.FinCont And Not PErr.HayError do begin
  384. If PPro.CogIdentificador(iden, idenM, uc) Then begin
  385. //-------------aqui se procesa el comando identificador
  386. If idenM = '$INCLUIR' Then //palabra reservada
  387. decodificar_INCLUIR
  388. // Else If idenM = '$CONSULTAR' Then //palabra reservada
  389. // decodificar_CONSULTAR
  390. Else If idenM = '$PARA' Then //palabra reservada
  391. decodificar_PARA
  392. Else If preProcFuncion(idenM) Then //preprocesa función
  393. //no hace nada porque ya se hizo
  394. else if ExpandirDefinido(idenM) then
  395. //no hace nada porque ya lo expandió
  396. else If l_delims.IndexOf(idenM) <> -1 Then begin //busca delimitador
  397. If uc = ' ' Then PPro.SacCar; //si último caracter fue espacio, retrocede.
  398. Result:= idenM; break end //encontro delimitador, sale.
  399. else //hay identificador pero no es reconocido
  400. PPro.Escribe(iden); //escribe identificador
  401. End Else //no es inicio de identificador
  402. ProcCaracter;
  403. end;
  404. //aquí puede haber llegado por error, por fin de contexto o por haber encontrado
  405. //algún delimitador.
  406. l_delims.Free;
  407. End;
  408. function procesarCuerpoPARA(vari: String; con: String;
  409. lPar: TStringList; lCon: TStringList; n1, n2: Integer; delims: string): string;
  410. {Procesa el cuerpo del $PARA para el caso "PRIMERO ... " O "HACER ...".
  411. Lee el lazao iterando en lPar y lCon, desde n1 hasta n2 hasta encontrar algúno de los
  412. delimitadores indicados. Devuelve el demimitador encontrado si no hubo error.}
  413. var i: Integer;
  414. posinic: TPosCont;
  415. npa, nco: Tdefinicion; //para manejar el reemplazo
  416. begin
  417. posinic := PPro.PosAct; //Guarda posición
  418. npa := nil; nco := nil; //inicia índices
  419. For i := n1 To n2 do begin
  420. PPro.PosAct := posinic; //Mueve al inicio
  421. //crea las variables para esta vuelta del lazo
  422. npa := CreaDefinicionDir(vari, lPar[i], npa);
  423. If lCon.Count > 0 Then nco := CreaDefinicionDir(con, lCon[i], nco);
  424. Result := procesarHastaDelim(delims); //Guarda delimitador
  425. if Result <> '' then continue; //encontró el final del bloque, pasa al siguiente
  426. If PErr.HayError Then break; //Hubo error, salir
  427. If PPro.FinCont Then begin //Se ha llegado al fin de archivo.
  428. PErr.GenError('Inesperado fin de archivo. No se encontró "FINPARA" del "PARA"', posinic);
  429. break;
  430. End;
  431. end;
  432. //aquí llega por error o por haber encontrado al delimitador
  433. EliminaDefinicion(npa); //limpia la memoria
  434. EliminaDefinicion(nco); //limpia la memoria
  435. End;
  436. procedure decodificar_PARA;
  437. {Decodifica la instruccion PARA var EN var1,var2,...varn [CON cond EN cond1,cond2,...condN] HACER
  438. <bloque>
  439. FINPARA}
  440. var vari : String; //variable "vari"
  441. con : String ; // variable "con"
  442. lPar : TStringList; //lista de ítems de para
  443. lCon : TStringList; //lista de ítems de con
  444. tmp : String;
  445. procedure VerificSiDefLista(var lst : TStringList);
  446. //Verifica si la lista de elementos es un lista definición, y si lo es, la expande.
  447. var def: Tdefinicion;
  448. begin
  449. If (lst.Count = 1) then begin //un solo elemento
  450. //puede ser definición lista
  451. def := definido(lst[0]); //la busca
  452. if def <> nil Then begin //es una definición lista
  453. lst.Clear; //la limpia
  454. def.LeeElementos(lst);
  455. If PErr.HayError Then Exit;
  456. If lst.Count = 0 Then begin //esta vacía
  457. PErr.GenError('La lista del $PARA no contiene elementos.', PPro.PosAct);
  458. Exit;
  459. end;
  460. End;
  461. End;
  462. End;
  463. begin
  464. lPar := TStringList.Create;
  465. lCon := TStringList.Create;
  466. try
  467. PErr.IniError;
  468. PPro.CapBlancos; //quita blancos después de $PARA
  469. //---------------------- coge la lista del "EN" -------------------------------
  470. vari := PPro.CogIdentificador; //coge nombre de la variable
  471. If vari = '' Then begin
  472. PErr.GenError('Se esperaba variable después del PARA', PPro.PosAct);
  473. Exit;
  474. End;
  475. PPro.CapBlancos; //quita blancos después de $PARA
  476. If UpCase(PPro.CogIdentificador()) <> 'EN' Then begin
  477. Perr.GenError('Se esperaba palabra "EN" después de ' + vari, PPro.PosAct);
  478. Exit;
  479. End;
  480. tmp := PPro.CogerLista(lPar,'HACER,CON,PRIMERO'); //toma lista de elementos EN ...
  481. If lPar.Count = 0 Then begin
  482. PErr.GenError('Se esperaba lista de elementos después del "EN"', PPro.PosAct);
  483. Exit;
  484. End;
  485. If PPro.FinCont Then begin
  486. PErr.GenError('Inesperado fin de archivo. Se esperaba fin de sentencia PARA..EN..HACER.', PPro.PosAct);
  487. Exit;
  488. End;
  489. VerificSiDefLista(lPar);
  490. If PErr.HayError Then Exit;
  491. //-------------------------- coge secuencia CON ----------------------------------------
  492. //CON cond EN cond1,cond2,...condN, si es que existe
  493. If tmp = 'CON' Then begin
  494. PPro.CapBlancos; //quita blancos
  495. con := PPro.CogIdentificador; //coge nombre de la variable cond
  496. If con = '' Then begin
  497. PErr.GenError('Se esperaba variable después del CON', PPro.PosAct);
  498. Exit;
  499. End;
  500. PPro.CapBlancos; //quita blancos
  501. If UpCase(PPro.CogIdentificador) <> 'EN' Then begin
  502. PErr.GenError('Se esperaba palabra "EN" después de ' + con, PPro.PosAct);
  503. Exit;
  504. End;
  505. tmp := PPro.CogerLista(lCon,'HACER,PRIMERO'); //toma lista de elementos EN ...
  506. If lCon.Count = 0 Then begin
  507. PErr.GenError('Se esperaba lista de elementos después de "CON ... EN"', PPro.PosAct);
  508. Exit;
  509. End;
  510. If PPro.FinCont Then begin
  511. PErr.GenError('Inesperado fin de archivo. Se esperaba fin de sentencia PARA..EN..CON..EN..HACER.', PPro.PosAct);
  512. Exit;
  513. End;
  514. VerificSiDefLista(lCon);
  515. If PErr.HayError Then Exit;
  516. If lCon.Count < lPar.Count Then begin
  517. PErr.GenError('Se esperaban ' + IntToStr(lPar.count) + ' variables en sentencia ..CON..EN..HACER.', PPro.PosAct);
  518. Exit;
  519. End;
  520. End;
  521. //-------------------------------continua con el cuerpo del HACER---------------------------------
  522. If tmp = 'HACER' Then begin //tmp debe tener el último delimitador
  523. //Expande lazo
  524. procesarCuerpoPARA(vari, con, lPar, lCon, 0, lPar.Count-1,'FINPARA');
  525. //Puede terminar con Error
  526. PPro.CapBlancos; //quita blancos hasta siguiente identificador
  527. end Else If tmp = 'PRIMERO' Then begin //sentencia con "PRIMERO"
  528. //Expande lazo
  529. tmp := procesarCuerpoPARA(vari, con, lPar, lCon, 0, 0,'FINPARA,HACER');
  530. If PErr.HayError Then Exit; //sale
  531. If tmp = 'HACER' Then begin //terminó con HACER
  532. //procesa sin considerar el primer elemento
  533. procesarCuerpoPARA(vari, con, lPar, lCon, 1, lPar.Count-1,'FINPARA');
  534. If PErr.HayError Then Exit;
  535. End;
  536. //se supone que terminó con FINPARA
  537. PPro.CapBlancos; //quita blancos hasta siguiente identificador
  538. end Else begin
  539. PErr.GenError('Se esperaba palabra reservada "HACER"', PPro.PosAct);
  540. Exit;
  541. End;
  542. finally
  543. lPar.Free; lCon.Free; //libera listas
  544. end;
  545. End;
  546. procedure decodificar_INCLUIR(IncluirMult: Boolean = False);
  547. {Decodifica la instruccion INCLUIR <archivo>
  548. que incluye un archivo dentro del archivo principal
  549. "IncluirMult" indica que se puede incluir múltiples veces el mismo
  550. archivo.}
  551. var arch : String;
  552. inc : Tinclusion;
  553. begin
  554. PErr.IniError;
  555. arch := PPRo.coger_ruta;
  556. arch := Trim(arch);
  557. // PPro.quitar_comentario(arch); //quita si hay comentarios "--"
  558. If arch = '' Then begin
  559. PErr.GenError('Se esperaba nombre de archivo en INCLUIR', PPRo.PosAct);
  560. Exit;
  561. End;
  562. If Pos('\', arch) = 0 Then begin //si no se especifica camino
  563. //le agrega camino de archivo de entrada
  564. If Pos('\', PPro.PosAct.arc) <> 0 Then //Si es que tiene ruta
  565. arch := ExtractFilePath(PPro.PosAct.arc) + arch;
  566. End;
  567. //se verifica si ya se ha incluido el archivo
  568. If (incluido(arch)<>nil) And Not IncluirMult Then begin
  569. //Ya esta incluido el archivo
  570. Exit; //sale, no lo vuelve a incluir
  571. End;
  572. //Verifica si existe
  573. If not FIleExists(arch) Then begin
  574. PErr.GenError('No Existe Archivo a INCLUIR: ' + arch, PPRo.PosAct);
  575. Exit;
  576. End;
  577. //Finalmente lo incluye
  578. If inclusiones.Count > MAX_INCLUSIONES Then begin
  579. PErr.GenError('Demasiados Archivos Incluidos.', PPRo.PosAct);
  580. Exit;
  581. End;
  582. inc := Tinclusion.Create;
  583. inc.arc := UpCase(arch); //guarda nombre mayuscula
  584. inc.pad := PPro.PosAct.arc; //guarda mnombre de padre
  585. inclusiones.Add(inc); //lo agrega
  586. preProcesarArc(arch); //preprocesa
  587. //se ha llegado al fin de archivo incluido, puede haber habido Error.
  588. End;
  589. procedure decodificar_FECHA_ACTUAL;
  590. //Decodifica la función fecha_actual(desplazamiento, formato)
  591. var desplaz : single; //desplazamiento de fecha
  592. formato, temp : String;
  593. nsem : byte;
  594. e : Texpre;
  595. begin
  596. If PPro.Capturar('(') = False Then begin
  597. PErr.GenError('Se esperaba "(" después de la función $FECHA_ACTUAL()', PPro.PosAct);
  598. Exit;
  599. End;
  600. e := CogExpresion(0);
  601. If PErr.HayError Then Exit;
  602. desplaz := e.valNum;
  603. If PPro.Capturar(',') = False Then begin
  604. PErr.GenError('Se esperaba ","', PPro.PosAct);
  605. Exit;
  606. End;
  607. formato := PPRo.CogCadena;
  608. If PErr.HayError Then Exit;
  609. If PPro.Capturar(')') = False Then begin
  610. PErr.GenError('Se esperaba ")"', PPro.PosAct);
  611. Exit;
  612. End;
  613. //verifica si hay "ww" en formato y lo reemplaza
  614. temp := Format('%2d',[WeekOfTheYear(Now + desplaz)]);
  615. formato := StringReplace(formato, 'ww', temp, [rfReplaceAll, rfIgnoreCase]);
  616. //escribe fecha actual
  617. DateTimeToString(temp, formato, Now + desplaz );
  618. PPro.Escribe(temp);
  619. End;
  620. procedure decodificar_EXPR;
  621. //Decodifica la función $expr(expresion)
  622. var
  623. e : Texpre;
  624. begin
  625. If PPro.Capturar('(') = False Then begin
  626. PErr.GenError('Se esperaba "(" después de la función $EXPR()', PPro.PosAct);
  627. Exit;
  628. End;
  629. e := CogExpresion(0);
  630. If PErr.HayError Then Exit;
  631. If PPro.Capturar(')') = False Then begin
  632. PErr.GenError('Se esperaba ")" después de la función $EXPR()', PPro.PosAct);
  633. Exit;
  634. End;
  635. PPro.Escribe(e.valTxt);
  636. End;
  637. procedure decodificar_FORMATO;
  638. //Decodifica la función $formato(expresion, formato)
  639. var e: Texpre;
  640. // expresion_cad: String; //expresion de cadena
  641. expresion_num: Single; //expresion numerica
  642. expresion_fec: TDateTime;
  643. formato : String;
  644. temp: string;
  645. function LeeFecha(e: Texpre): TDateTime;
  646. //procesa el caso en el que la expresión es de tipo "ww99/9999". Se supone que "e" es cadena.
  647. var cad: string;
  648. sem, ano : Integer;
  649. begin
  650. cad := e.valTxt;
  651. If (length(cad) = 8) and (cad[1] = 'w') and (cad[4] = '/') Then begin
  652. //debe ser formato de semana: "ww99/9999" verifica
  653. If not TryStrToInt(copy(cad, 2, 2),sem) or
  654. not TryStrToInt(copy(cad, 5, 4),ano) Then begin
  655. PErr.GenError('Error en formato de semana. El formato es: w##/####', PPro.PosAct);
  656. Exit;
  657. End;
  658. //devuvelve la fecha solicitada
  659. Result := EncodeDateWeek(ano, sem);
  660. end else begin //debe ser un formato de fecha normal
  661. result := e.valFec; //Puede dar error
  662. if Perr.HayError then begin //precisa el error
  663. PErr.GenError('Fecha inválida', PPro.PosAct);
  664. Exit;
  665. end;
  666. end;
  667. end;
  668. begin
  669. If PPro.Capturar('(') = False then begin
  670. PErr.GenError('Se esperaba "(" después de la función $FORMATO()', PPro.PosAct);
  671. Exit;
  672. End;
  673. //lee primer parámetro
  674. e := CogExpresion(0); //puede ser constante o definición
  675. If PErr.HayError Then Exit;
  676. if e.tip = TIP_CAD then begin
  677. //la cadena debe ser una fecha
  678. //Aquí se tiene siempre una cadena
  679. expresion_fec := LeeFecha(e); //toma fecha
  680. if PErr.HayError then exit; //puede dar error
  681. If PPro.Capturar(',') = False Then begin
  682. PErr.GenError('Se esperaba ","', PPro.PosAct);
  683. Exit;
  684. End;
  685. //toma segundo parámetro
  686. formato := PPro.CogCadena; //toma el formato
  687. If PErr.HayError Then Exit;
  688. If PPro.Capturar(')') = False Then begin
  689. PErr.GenError('Se esperaba ")"', PPro.PosAct);
  690. Exit;
  691. End;
  692. //verifica si hay "ww" en formato y lo reemplaza
  693. temp := Format('%2d',[WeekOfTheYear(expresion_fec)]);
  694. formato := StringReplace(formato, 'ww', temp, [rfReplaceAll, rfIgnoreCase]);
  695. //escribe la fecha
  696. DateTimeToString(temp, formato, expresion_fec);
  697. PPro.Escribe(temp); //escribe fecha actual
  698. end else if e.tip = TIP_NUM then begin
  699. end else begin
  700. //Solo se maneja tipos de dato de cadena (fecha) { TODO : Incluir formato para números }
  701. PErr.GenError('Se esperaba expresión de tipo cadena-fecha', PPro.PosAct);
  702. Exit;
  703. end;
  704. End;
  705. Function preProcFuncion(identif: String): Boolean;
  706. //Hace el preprocesamiento de una función
  707. //Si no era una función válida, devuleve falso
  708. var temp: String;
  709. begin
  710. preProcFuncion := True; //se asume que es función
  711. If identif = '$FECHA_ACTUAL' Then //funcion fecha_actual()
  712. decodificar_FECHA_ACTUAL
  713. Else If identif = '$FORMATO' Then //funcion formato()
  714. decodificar_FORMATO
  715. Else {If identif = '$INTERVALO_SEMANA' Then //funcion intervalo_semana()
  716. decodificar_INTERVALO_SEMANA
  717. Else If identif = '$PSQL_REINIC' Then //funcion psql_reinic()
  718. decodificar_PSQL_REINIC
  719. Else If identif = '$COLUMNAS' Then //funcion columna()
  720. decodificar_COLUMNAS
  721. Else If identif = '$INDICES' Then //funcion indices()
  722. decodificar_INDICES
  723. Else If identif = '$INFOVISTA' Then //funcion infovista()
  724. decodificar_INFOVISTA
  725. Else If identif = '$INFOTABLA' Then //funcion infotabla()
  726. decodificar_INFOTABLA
  727. Else }If identif = '$NOM_ACTUAL' Then begin //variable de nombre actual de archivo
  728. If PPRo.VerCarN(2) = '()' Then
  729. begin PPro.CogCar; PPro.CogCar end; //para facilitar el uso de esta función
  730. temp := ChangeFileExt(ExtractFileName(arcEnt),''); //usa siempre el archivo de entrada
  731. PPro.Escribe(temp); //escribe solo el nombre de archivo
  732. end
  733. Else If identif = '$DIR_ACTUAL' Then begin //variable de nombre actual del directorio
  734. If PPro.VerCarN(2) = '()' Then
  735. begin PPro.CogCar; PPro.CogCar end; //para facilitar el uso de esta función
  736. temp := ExtractFilePath(arcEnt); //usa siempre el archivo de entrada
  737. if temp = '' then exit; //no hay ruta, sale
  738. If temp[length(temp)] = '\' Then temp := copy(temp, 1, Length(temp) - 1);
  739. PPro.Escribe(temp); //escribe solo el camino sin "\"
  740. end Else If identif = '$EXPR' Then //funcion expresión()
  741. decodificar_EXPR
  742. // Else If identif = '$LEE_CADENA' Then //funcion expresión()
  743. // decodificar_LEECADENA
  744. Else
  745. //No era función
  746. preProcFuncion := False;
  747. End;
  748. {procedure decodificar_CONNECT;
  749. //Procesa la sentecnia CONNECT para determinar la cadena de conexión que se usará en la
  750. //consulta
  751. begin
  752. If cad_con = '' Then begin //Es la primera cadena de conexión de la consulta
  753. //No se escribe, sólo se lee para usarla en la llamada al SQLPLUS
  754. cad_con := Trim(PPro.CogerHastaComent);
  755. if cad_con = '' then begin
  756. PErr.GenError('Se esperaba cadena de conexión.', PPro.PosAct);
  757. exit;
  758. end;
  759. //quita punto y coma final si existe
  760. If cad_con[length(cad_con)] = ';' Then
  761. cad_con := copy(cad_con, 1, Length(cad_con) - 1);
  762. end else //no es la primera cadena de conexión
  763. PPro.Escribe('CONNECT'); //escribe CONNECT
  764. end;}
  765. procedure preProcesarAct;
  766. //Realiza el preprocesamiento del Contenido actual
  767. var iden, idenM: String;
  768. uc : char;
  769. begin
  770. //-----------------------------------------
  771. While Not PPro.FinCont do begin
  772. If PErr.HayError Then break;
  773. If PPro.CogIdentificador(iden, idenM, uc) Then begin
  774. //-------------aqui se procesa el identificadorencontrado
  775. {If idenM = 'CONNECT' Then
  776. decodificar_CONNECT
  777. Else }If idenM = '$DEFINIR' Then //palabra reservada
  778. decodificar_DEFINIR
  779. Else If idenM = '$REDEF' Then //palabra reservada
  780. decodificar_REDEF
  781. Else If idenM = '$INCLUIR' Then //palabra reservada
  782. decodificar_INCLUIR
  783. // ElseIf idenM = '$CONSULTAR' Then //palabra reservada
  784. // decodificar_CONSULTAR
  785. Else If idenM = '$PARA' Then //palabra reservada
  786. decodificar_PARA
  787. Else If preProcFuncion(idenM) Then //preprocesa función
  788. //no hace nada porque ya se hizo
  789. else if ExpandirDefinido(idenM) then
  790. //no hace nada porque ya lo expandió
  791. else //hay identificador pero no es reconocido
  792. PPro.Escribe(iden); //escribe identificador
  793. end else
  794. ProcCaracter;
  795. end;
  796. End;
  797. procedure preProcesarCad(txt: String; archivo: String);
  798. //Preprocesa una cadena de texto. No modifica la posición ni el contenido actual
  799. //Escribe su salida en el dispositivo de salida actual.
  800. var con: TPosCont;
  801. begin
  802. PErr.IniError;
  803. con := PPro.PosAct; //Guarda posición y contenido actual
  804. PPro.NuevoContexEntTxt(txt, trim(archivo)); //Crea nuevo contenido
  805. If PErr.HayError Then Exit;
  806. preProcesarAct;
  807. PPro.PosAct := con; //recupera el contenido actual
  808. End;
  809. procedure preProcesarArc(archivo: String);
  810. //Preprocesa un archivo de texto. No modifica la posición ni el contenido actual
  811. //Escribe su salida en el dispositivo de salida actual.
  812. var con: TPosCont;
  813. begin
  814. PErr.IniError;
  815. con := PPro.PosAct; //Guarda posición y contenido actual
  816. PPro.NuevoContexEntArc(Trim(archivo)); //Crea nuevo contenido
  817. If PErr.HayError Then Exit;
  818. preProcesarAct;
  819. PPro.PosAct := con; //recupera el contenido actual
  820. //¿¿¿Y no destruye el contexto actual???
  821. End;
  822. procedure InicPreproc;
  823. //Inicia el preprocesamiento
  824. begin
  825. Perr.IniError;
  826. //preprocesa
  827. cad_con := ''; //Inicia la primera cadena de conexión de la consulta
  828. definiciones.Clear; //inicializa el numero de definiciones "$DEFINIR"
  829. inclusiones.Clear; //inicializa el numero de inclusiones "$INCLUIR"
  830. PPro.Iniciar; //Inicia contextos para trabajo
  831. PPro.NuevoContexSal; //Crea contexto de salida
  832. //variable predefinida
  833. CreaDefinicionDir('$horas', '00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23');
  834. CreaDefinicionDir('$meses', '01 02 03 04 05 06 07 08 09 10 11 12');
  835. end;
  836. procedure PreProcesar(arc: String; txt: String; var cadcon0: string);
  837. {Realiza el preprocesamiento de un archivo o un texto. Si "txt" <> "", se procesa "txt",
  838. de otra forma, procesa el archivo "arc". La salida preprocesada se debe extraer de
  839. PPro.
  840. Si se encuentra una sentencia de tip CONNECT en la consulta, se devolverá la cadena
  841. de conexión, en "cadcon0", de otra forma se devolverá una cadena vacía.
  842. Punto de entrada único para el preprocesamiento.}
  843. begin
  844. cadcon0 := '';
  845. arcEnt := Arc; //Guarda el nombre del archivo de entrada para el procesamiento.
  846. InicPreproc;
  847. If txt = '' Then //Procesa archivo
  848. preProcesarArc(arcEnt)
  849. Else //Procesa cadena
  850. preProcesarCad(txt,arcEnt); {indica archivo de entrada para poder procesar las funciones
  851. $Dir_actual y $Nom_actual}
  852. //Si hubo error, sale actualizando variables de error
  853. if PErr.HayError then exit;
  854. if cad_con <> '' then cadcon0 := cad_con; //la cadena de conexión de la consulta prevalece
  855. End;
  856. { Tdefinicion }
  857. procedure Tdefinicion.Expandir;
  858. var con0: TPosCont; //Posición de contenido
  859. iden, idenM: String;
  860. uc : char; //último caracter
  861. begin
  862. If tip = TD_DIR Then begin
  863. //Es de tipo directo, lo expande
  864. PPro.Escribe(txt);
  865. Exit; //Sale no más
  866. End;
  867. //Expande definición de tipo contexto
  868. con0 := PPro.PosAct; //guarda contenido actual
  869. PPro.PosAct := con; //fija a contenido de la definicion
  870. //expande hasta el bloque DEFINIDO
  871. If PPro.VerCar = ' ' Then PPro.CogCar; //ignora el primer espacio si lo hay
  872. While Not PPro.FinCont do begin
  873. If PErr.HayError Then break;
  874. If PPro.CogIdentificador(iden, idenM, uc) Then begin
  875. //-------------aqui se procesa el comando encontrado
  876. If idenM = '$INCLUIR' Then //palabra definida
  877. decodificar_INCLUIR(True)
  878. // ElseIf iden = '$CONSULTAR' Then //palabra reservada
  879. // Call decodificar_CONSULTAR
  880. Else If idenM = '$PARA' Then //palabra reservada
  881. decodificar_PARA
  882. Else If preProcFuncion(idenM) Then //preprocesa función
  883. //no hace nada porque ya se hizo
  884. else if ExpandirDefinido(idenM) then
  885. //no hace nada porque ya lo expandió
  886. else if idenM = 'FINDEFINIR' Then begin
  887. If uc = ' ' Then PPro.SacCar; //si último caracter fue espacio, retrocede.
  888. break; //terminó su trabajo
  889. end else //hay identificador pero no es reconocido
  890. PPro.Escribe(iden); //escribe identificador
  891. end Else //no es inicio de identificador
  892. ProcCaracter;
  893. end;
  894. if PPro.FinCont then begin;
  895. //este error no deberia producirse ya que se ha examinado anteriormente
  896. //el archivo y se encontro el FINDEFINIR de otra forma no se habria llegado aqui
  897. PErr.GenError('Sorpresa!!!. No se encontro "FINDEFINIR" del "$DEFINIR"', PPro.PosAct);
  898. exit;
  899. end;
  900. PPro.PosAct := con0; //Devuelve al contenido de trabajo
  901. end;
  902. function Tdefinicion.ValTxt: string;
  903. //Devuelve la definición expandida como una cadena.
  904. begin
  905. If tip = TD_DIR Then
  906. Result := txt
  907. else begin //es de contexto
  908. PPro.NuevoContexSal; //crea nuevo contexto de salida
  909. Expandir; //expande en nuevo contexto
  910. //Puede devolver error
  911. Result := Ppro.cadenaSal; //copia resultado
  912. { TODO : Ver y corregir, por qué una definición de tipo
  913. COMO .. FINDEFINIR de una sola linea, se expande con un salto al final }
  914. PPro.QuitaContexSal; //Elimina contexto creado
  915. end;
  916. end;
  917. procedure Tdefinicion.FijTxt(t: string);
  918. begin
  919. tip := TD_DIR; //la fuerza a definición directa, o de otra forma no tiene sentido
  920. //cambiar su valor
  921. txt := t; //cambia su valor
  922. end;
  923. procedure Tdefinicion.LeeElementos(elem: TStringList);
  924. {Lee los elementos de la definición, y los agrega al areglo "elem". Se debe usar con
  925. definiciones de tipo lista. Los eleemntos están separados por blancos. }
  926. begin
  927. PPro.NuevoContexEntTxt(ValTxt, con.arc); //Pone expansión de definición en nuevo contexto
  928. while not PPro.FinCont do begin //explora expansión
  929. elem.Add(Ppro.CogElemento);
  930. end;
  931. PPro.QuitaContexEnt; //elimina el contexto
  932. end;
  933. initialization
  934. //crea objetos
  935. definiciones := TListaDef.Create(true);
  936. inclusiones := TListaInc.Create(true);
  937. arcEnt := ''; //inicia archivo de entrada
  938. finalization
  939. definiciones.Free;
  940. inclusiones.Free;
  941. end.