FoxProgTools.Mod 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  1. MODULE FoxProgTools; (** AUTHOR "fof"; PURPOSE "Oberon Compiler: Programming Tools"; **)
  2. (* (c) fof ETH Zürich, 2009 *)
  3. IMPORT Streams,Options,Commands,Files,Strings, Basic := FoxBasic;
  4. TYPE
  5. NameEntry = POINTER TO RECORD
  6. name: ARRAY 265 OF CHAR;
  7. END;
  8. NameList = OBJECT(Basic.List)
  9. PROCEDURE & Init;
  10. BEGIN InitList(256)
  11. END Init;
  12. PROCEDURE AddName(CONST name: ARRAY OF CHAR);
  13. VAR entry: NameEntry;
  14. BEGIN
  15. NEW(entry);
  16. COPY(name, entry.name);
  17. Add(entry)
  18. END AddName;
  19. PROCEDURE GetName(index: LONGINT; VAR name: ARRAY OF CHAR);
  20. VAR
  21. any: ANY;
  22. BEGIN
  23. any := Get(index);
  24. ASSERT(any IS NameEntry);
  25. COPY(any(NameEntry).name, name)
  26. END GetName;
  27. PROCEDURE ContainsName(CONST otherName: ARRAY OF CHAR): BOOLEAN;
  28. VAR
  29. i: LONGINT;
  30. name: ARRAY 256 OF CHAR;
  31. BEGIN
  32. FOR i := 0 TO Length() - 1 DO
  33. GetName(i, name);
  34. IF name = otherName THEN RETURN TRUE END
  35. END;
  36. RETURN FALSE
  37. END ContainsName;
  38. PROCEDURE DumpNames(w: Streams.Writer);
  39. VAR
  40. i: LONGINT;
  41. name: ARRAY 256 OF CHAR;
  42. BEGIN
  43. w.Int(Length(), 0); w.String(" names:"); w.Ln;
  44. FOR i := 0 TO Length() - 1 DO
  45. GetName(i, name);
  46. w.String(name); w.Ln
  47. END;
  48. w.Ln
  49. END DumpNames;
  50. PROCEDURE SortNames;
  51. BEGIN Sort(NameComparator)
  52. END SortNames;
  53. END NameList;
  54. (** string comparator function that is used to sort strings alphabetically **)
  55. PROCEDURE NameComparator(left, right: ANY): BOOLEAN;
  56. VAR
  57. result: SHORTINT;
  58. i: LONGINT;
  59. leftChar, rightChar: CHAR;
  60. BEGIN
  61. result := 0; i := 0;
  62. REPEAT
  63. leftChar := left(NameEntry).name[i];
  64. rightChar := right(NameEntry).name[i];
  65. IF leftChar < rightChar THEN result := -1
  66. ELSIF leftChar > rightChar THEN result := +1
  67. END;
  68. INC(i)
  69. UNTIL (result # 0) OR (leftChar = 0X) OR (rightChar = 0X);
  70. RETURN result < 0
  71. END NameComparator;
  72. PROCEDURE ParseARMInstructionSet*(context: Commands.Context);
  73. CONST
  74. PrependIS = FALSE;
  75. TYPE
  76. Operand = RECORD
  77. type: ARRAY 256 OF CHAR;
  78. mask: SET;
  79. END;
  80. VAR
  81. isThumb, comma: BOOLEAN;
  82. i, pos, numBits, numOps: LONGINT;
  83. char: CHAR;
  84. ones, mask: SET;
  85. filename, mnemonic, token, flagString, encodingName, pattern, type: ARRAY 256 OF CHAR;
  86. operands: ARRAY 10 OF Operand;
  87. operand: Operand;
  88. file: Files.File;
  89. reader: Files.Reader;
  90. encodingNames: NameList;
  91. PROCEDURE AppendMaskName(VAR string: ARRAY OF CHAR; mask: SET);
  92. VAR
  93. j, start: LONGINT;
  94. inside, first: BOOLEAN;
  95. numString: ARRAY 32 OF CHAR;
  96. BEGIN
  97. IF mask = {} THEN
  98. Strings.Append(string, "Implicit");
  99. ELSE
  100. first := TRUE;
  101. inside := FALSE;
  102. FOR j := 0 TO 31 + 1 DO
  103. IF (j < 32) & (j IN mask) THEN
  104. IF ~inside THEN
  105. IF first THEN first := FALSE ELSE Strings.Append(string, "and") END;
  106. Strings.IntToStr(j, numString);
  107. Strings.Append(string, numString);
  108. start := j;
  109. inside := TRUE
  110. END
  111. ELSE
  112. IF inside THEN
  113. IF j - 1 > start THEN
  114. Strings.Append(string, "to");
  115. Strings.IntToStr(j - 1, numString);
  116. Strings.Append(string, numString);
  117. END;
  118. inside := FALSE
  119. END
  120. END
  121. END;
  122. END
  123. END AppendMaskName;
  124. PROCEDURE Error(CONST message: ARRAY OF CHAR);
  125. BEGIN
  126. context.out.Ln;
  127. context.out.String("Error: ");
  128. context.out.String(message);
  129. context.out.Ln;
  130. context.out.Update
  131. END Error;
  132. (*
  133. PROCEDURE Log(CONST message: ARRAY OF CHAR);
  134. BEGIN
  135. context.out.Ln;
  136. context.out.String("Log: ");
  137. context.out.String(message);
  138. context.out.Ln;
  139. context.out.Update
  140. END Log;
  141. *)
  142. PROCEDURE IsUpperCase(char: CHAR): BOOLEAN;
  143. BEGIN RETURN (ORD(char) >= ORD('A')) & (ORD(char) <= ORD('Z'))
  144. END IsUpperCase;
  145. BEGIN
  146. context.arg.SkipWhitespace; context.arg.String(filename);
  147. IF filename # "" THEN
  148. file := Files.Old(filename);
  149. IF file = NIL THEN Error("file not found"); RETURN END;
  150. context.out.String("parsing file "); context.out.String(filename); context.out.Ln; context.out.Ln; context.out.Update;
  151. NEW(reader, file, 0);
  152. mnemonic := "";
  153. NEW(encodingNames);
  154. reader.Token(token);
  155. WHILE reader.Available() > 0 DO
  156. IF token = "" THEN
  157. reader.SkipWhitespace
  158. ELSIF token[0] = '%' THEN (* comment *)
  159. reader.SkipLn
  160. ELSIF (token = "T") OR (token = "A") THEN
  161. IF mnemonic = "" THEN Error("no mnemonic specified"); RETURN END;
  162. isThumb := token = 'T';
  163. (* parse flags *)
  164. reader.SkipWhitespace; reader.Token(token);
  165. flagString := "{";
  166. comma := FALSE;
  167. i := 0;
  168. WHILE token[i] # 0X DO
  169. char := token[i];
  170. IF char # '-' THEN
  171. IF comma THEN Strings.Append(flagString, ", "); END;
  172. Strings.Append(flagString, "flag");
  173. IF IsUpperCase(char) THEN Strings.Append(flagString, "Always") END;
  174. Strings.AppendChar(flagString, Strings.UP(char));
  175. comma := TRUE
  176. END;
  177. INC(i)
  178. END;
  179. Strings.Append(flagString, "}");
  180. (* reset operands *)
  181. FOR i := 0 TO LEN(operands) - 1 DO
  182. operand.type := "?";
  183. operand.mask := {};
  184. operands[i] := operand
  185. END;
  186. (* parse bit pattern *)
  187. reader.SkipWhitespace;
  188. pattern := "";
  189. i := 0;
  190. reader.Char(char);
  191. WHILE (char # 9X) & ~reader.EOLN() DO
  192. IF char # ' ' THEN
  193. pattern[i] := char;
  194. INC(i)
  195. END;
  196. reader.Char(char)
  197. END;
  198. pattern[i] := 0X;
  199. numBits := i;
  200. IF (numBits MOD 16) # 0 THEN Error("number of bits in pattern not a multiple of 16");
  201. context.out.String(pattern); context.out.Ln; context.out.Update;
  202. RETURN
  203. END;
  204. ones := {};
  205. mask := {};
  206. i := 0;
  207. WHILE pattern[i] # 0X DO
  208. pos := numBits - 1 - i;
  209. char := pattern[i];
  210. CASE char OF
  211. | '0': INCL(mask, pos)
  212. | '1': INCL(mask, pos); INCL(ones, pos)
  213. | '-': (* ignore *)
  214. | '+': INCL(ones, pos)
  215. | 'a' .. 'f': INCL(operands[ORD(char) - ORD('a')].mask, pos)
  216. ELSE (* ignore *)
  217. END;
  218. INC(i)
  219. END;
  220. (* parse operand types *)
  221. i := 0;
  222. WHILE ~reader.EOLN() DO
  223. reader.SkipWhitespace;
  224. reader.Token(token);
  225. IF token # "-" THEN operands[i].type := token; INC(i) END
  226. END;
  227. numOps := i;
  228. (* print Oberon line of code that registers this encoding *)
  229. context.out.String("EnterInstruction(instr"); context.out.String(mnemonic);
  230. context.out.String(", "); IF isThumb THEN context.out.String("Thumb") ELSE context.out.String("ARM") END;
  231. context.out.String(", "); context.out.Int(numBits DIV 16, 0);
  232. context.out.String(", "); context.out.Set(ones);
  233. context.out.String(", "); context.out.Set(mask);
  234. context.out.String(", "); context.out.String(flagString);
  235. context.out.Update;
  236. FOR i := 0 TO numOps - 1 DO
  237. operand := operands[i];
  238. context.out.String(", ");
  239. (* compose encoding name *)
  240. encodingName := "enc";
  241. IF PrependIS THEN IF isThumb THEN Strings.AppendChar(encodingName, 'T') ELSE Strings.AppendChar(encodingName, 'A') END END;
  242. (* manual names: *)
  243. type := operand.type;
  244. IF type = "r" THEN Strings.Append(encodingName, "Reg");
  245. ELSIF type = "isr" THEN Strings.Append(encodingName, "ImmShReg")
  246. ELSIF type = "rsr" THEN Strings.Append(encodingName, "RegShReg")
  247. ELSIF type = "i" THEN Strings.Append(encodingName, "Imm")
  248. ELSIF type = "wi" THEN Strings.Append(encodingName, "WideImm")
  249. ELSIF type = "l" THEN Strings.Append(encodingName, "Label")
  250. ELSIF type = "l-" THEN Strings.Append(encodingName, "ForwardLabel")
  251. ELSIF type = "l+" THEN Strings.Append(encodingName, "BackwardLabel")
  252. ELSIF type = "b" THEN Strings.Append(encodingName, "Bitfield")
  253. ELSIF type = "sp" THEN Strings.Append(encodingName, "SP")
  254. ELSIF type = "1" THEN Strings.Append(encodingName, "Op1")
  255. ELSIF type = "*" THEN (* ignore *)
  256. ELSE Error("unknown operand type found"); RETURN
  257. END;
  258. (* alternative, which works for arbitrary type strings
  259. COPY(Strings.UpperCaseInNew(operand.type)^, type);
  260. *)
  261. AppendMaskName(encodingName, operand.mask);
  262. context.out.String(encodingName);
  263. IF ~encodingNames.ContainsName(encodingName) THEN encodingNames.AddName(encodingName) END;
  264. END;
  265. context.out.String(");"); context.out.Ln;
  266. context.out.Update
  267. ELSE
  268. (* start of a new mnemonic *)
  269. mnemonic := token
  270. END;
  271. reader.Token(token)
  272. END;
  273. context.out.Ln; context.out.Ln;
  274. encodingNames.SortNames;
  275. encodingNames.DumpNames(context.out);
  276. context.out.Update
  277. ELSE
  278. Error("filename missing")
  279. END
  280. END ParseARMInstructionSet;
  281. (* e.g. InstructionBits "100xx0x0x" ~
  282. 0: should be 0
  283. 1: should be 1
  284. x: free
  285. *)
  286. PROCEDURE InstructionBits*(context: Commands.Context);
  287. VAR
  288. i, length, bitPos: LONGINT;
  289. shouldBeOnes, mask: SET;
  290. pattern: ARRAY 33 OF CHAR;
  291. w: Streams.Writer;
  292. options: Options.Options;
  293. BEGIN
  294. NEW(options);
  295. IF options.Parse(context.arg, context.error) THEN
  296. IF context.arg.GetString(pattern) THEN
  297. w := context.out;
  298. length := 0;
  299. WHILE pattern[length] # 0X DO INC(length) END;
  300. IF (length # 16) & (length # 32) THEN
  301. context.error.String("Error: invalid pattern length: ");
  302. context.error.Int(length, 0);
  303. context.error.Ln
  304. ELSE
  305. FOR i := 0 TO length - 1 DO
  306. bitPos := length - 1 - i;
  307. CASE pattern[i] OF
  308. | '0': INCL(mask, bitPos)
  309. | '1': INCL(mask, bitPos); INCL(shouldBeOnes, bitPos)
  310. ELSE (* ignore *)
  311. END
  312. END;
  313. w.Set(shouldBeOnes); w.String(", "); w.Set(mask); w.Ln
  314. END
  315. END
  316. END
  317. END InstructionBits;
  318. PROCEDURE Enum*(context: Commands.Context);
  319. VAR w: Streams.Writer; nr: LONGINT; options: Options.Options; export,incremental,hex: BOOLEAN; start: LONGINT;
  320. name,oldname,prefix: ARRAY 256 OF CHAR; lf: LONGINT;
  321. (** get next symbol **)
  322. PROCEDURE GetNextSymbol(VAR s: ARRAY OF CHAR ): BOOLEAN;
  323. CONST EOT=0X;
  324. VAR ch: CHAR; i: LONGINT;
  325. PROCEDURE SkipBlanks;
  326. BEGIN
  327. WHILE ch <= " " DO (*ignore control characters*)
  328. IF ch = EOT THEN RETURN
  329. ELSE ch := context.arg.Get();
  330. END
  331. END;
  332. END SkipBlanks;
  333. PROCEDURE Comment;
  334. VAR i: LONGINT;
  335. BEGIN
  336. i := 0;
  337. LOOP
  338. IF (ch = EOT) OR (i>256) THEN EXIT
  339. ELSIF ch = "(" THEN
  340. w.Char(ch); ch := context.arg.Get();
  341. IF ch = "*" THEN
  342. w.Char(ch); ch := context.arg.Get();
  343. Comment()
  344. END;
  345. ELSIF ch = "*" THEN
  346. w.Char(ch);
  347. ch := context.arg.Get();
  348. IF ch = ")" THEN
  349. w.Char(ch); ch := context.arg.Get();
  350. EXIT
  351. END;
  352. ELSE w.Char(ch); ch := context.arg.Get(); INC(i);
  353. END;
  354. END;
  355. END Comment;
  356. BEGIN
  357. ch := context.arg.Get();
  358. SkipBlanks; i := 0;
  359. LOOP
  360. IF (ch <= " ") OR (ch = EOT) OR (i>128) THEN EXIT
  361. ELSIF ch = "(" THEN
  362. ch := context.arg.Get();
  363. IF ch = "*" THEN
  364. ch := context.arg.Get();
  365. IF (nr-start) MOD lf # 0 (* avoid two linefeeds *) THEN w.Ln END;
  366. w.String("(*");
  367. Comment();
  368. w.Ln; start := nr;
  369. SkipBlanks;
  370. ELSE s[i] := "("; INC(i);
  371. END;
  372. ELSE s[i] := ch; INC(i); ch := context.arg.Get();
  373. END;
  374. END;
  375. s[i] := 0X;
  376. RETURN (i>0);
  377. END GetNextSymbol;
  378. BEGIN
  379. NEW(options);
  380. options.Add("e", "export", Options.Flag);
  381. options.Add("i", "incremental", Options.Flag);
  382. options.Add("s", "start", Options.Integer);
  383. options.Add("h","hex",Options.Flag);
  384. options.Add("l","linefeed",Options.Integer);
  385. options.Add("p","prefix",Options.String);
  386. IF options.Parse(context.arg,context.error) THEN
  387. w := context.out;
  388. IF ~options.GetInteger("s",start) THEN start := 0 END;
  389. export := options.GetFlag("e");
  390. incremental := options.GetFlag("i");
  391. hex := options.GetFlag("h");
  392. IF ~options.GetString("p", prefix) THEN prefix := "" END;
  393. IF ~options.GetInteger("l",lf) THEN lf := MAX(LONGINT) END;
  394. nr := start;
  395. WHILE GetNextSymbol(name) DO
  396. w.String(prefix);
  397. w.String(name);
  398. IF export THEN w.String("*"); END;
  399. w.String("= ");
  400. IF incremental THEN
  401. IF oldname = "" THEN
  402. IF hex THEN w.Hex(nr,1); w.String("H"); ELSE w.Int(nr,1) END;
  403. ELSE w.String(oldname); w.String("+1");
  404. END;
  405. ELSE
  406. IF hex THEN w.Hex(nr,1); w.String("H"); ELSE w.Int(nr,1) END;
  407. END;
  408. w.String("; ");
  409. IF (nr-start+1) MOD lf = 0 THEN w.Ln END;
  410. INC(nr);
  411. oldname := name;
  412. (* context.arg.GetString(name); *)
  413. END;
  414. w.Update;
  415. END;
  416. END Enum;
  417. PROCEDURE ParseAMDInstructionSet*(context: Commands.Context);
  418. CONST TAB = 9X; CR = 0DX; LF = 0AX;
  419. TYPE
  420. Instruction=POINTER TO RECORD
  421. op1,op2,op3,opcode,target,bitwidth: ARRAY 256 OF CHAR;
  422. next: Instruction;
  423. END;
  424. Mnemonic= POINTER TO RECORD
  425. name: ARRAY 32 OF CHAR;
  426. firstInstruction,lastInstruction: Instruction;
  427. next: Mnemonic;
  428. END;
  429. Replacement = POINTER TO RECORD
  430. from,to: ARRAY 256 OF CHAR;
  431. next: Replacement;
  432. END;
  433. TYPE Replacer= OBJECT
  434. VAR first,last: Replacement;
  435. PROCEDURE &Init;
  436. BEGIN first := NIL; last := NIL;
  437. END Init;
  438. PROCEDURE Add(CONST src,dest: ARRAY OF CHAR);
  439. VAR r: Replacement;
  440. BEGIN
  441. NEW(r); COPY(src,r.from); COPY(dest,r.to);
  442. IF first = NIL THEN first := r; last := r ELSE last.next := r; last := r END;
  443. END Add;
  444. PROCEDURE Do(VAR src: ARRAY OF CHAR);
  445. VAR pos: LONGINT; r: Replacement;
  446. BEGIN
  447. r := first;
  448. WHILE r # NIL DO
  449. pos := Strings.Pos(r.from,src);
  450. IF pos # -1 THEN
  451. Strings.Delete(src,pos,Strings.Length(r.from));
  452. Strings.Insert(r.to,src,pos);
  453. END;
  454. r := r.next;
  455. END;
  456. END Do;
  457. END Replacer;
  458. VAR fileName,instr: ARRAY 256 OF CHAR; w: Streams.Writer; reader: Files.Reader; file: Files.File; ch: CHAR;
  459. line: ARRAY 1024 OF CHAR;
  460. firstMnemonic,prevmnemonic,mnemonic : Mnemonic;
  461. instruction: Instruction;
  462. operandReplacer: Replacer;
  463. cpuoptionReplacer: Replacer;
  464. bitwidthReplacer: Replacer;
  465. numberMnemonics: LONGINT;
  466. numberInstructions : LONGINT;
  467. maxMnemonicNameLength: LONGINT;
  468. maxOpcodeLength: LONGINT;
  469. PROCEDURE Priority(i: Instruction): LONGINT;
  470. VAR prio: LONGINT;
  471. PROCEDURE OP(CONST o: ARRAY OF CHAR): LONGINT;
  472. BEGIN
  473. IF o = "" THEN
  474. RETURN 10
  475. ELSIF (o = "reg8") OR (o = "reg16") OR (o="reg32") OR (o="reg64") THEN
  476. RETURN 5
  477. ELSE
  478. RETURN 0
  479. END;
  480. END OP;
  481. BEGIN
  482. prio := 0;
  483. prio := OP(i.op1) + OP(i.op2) + OP(i.op3);
  484. RETURN prio
  485. END Priority;
  486. PROCEDURE InsertSorted(VAR first: Instruction; this: Instruction);
  487. VAR temp: Instruction;
  488. BEGIN
  489. IF (first = NIL) OR (Priority(this)>Priority(first)) THEN
  490. this.next := first;
  491. first := this;
  492. ELSE
  493. temp := first;
  494. WHILE (temp.next # NIL) & (Priority(temp.next) >= Priority(this)) DO
  495. temp := temp.next;
  496. END;
  497. this.next := temp.next;
  498. temp.next := this;
  499. END;
  500. END InsertSorted;
  501. PROCEDURE SortInstructions(VAR first: Instruction);
  502. VAR temp,next,newfirst: Instruction;
  503. BEGIN
  504. newfirst := NIL;
  505. temp := first;
  506. WHILE temp # NIL DO
  507. next := temp.next;
  508. InsertSorted(newfirst,temp);
  509. temp := next;
  510. END;
  511. first := newfirst;
  512. END SortInstructions;
  513. PROCEDURE GetCh;
  514. BEGIN
  515. ch := reader.Get();
  516. END GetCh;
  517. PROCEDURE GetLine(VAR line: ARRAY OF CHAR);
  518. VAR i : LONGINT;
  519. BEGIN
  520. i := 0;
  521. WHILE(ch # CR) & (ch # LF) & (ch # 0X) DO
  522. line[i] := ch; INC(i);
  523. GetCh();
  524. END;
  525. line[i] := 0X;
  526. WHILE(ch = CR) OR (ch=LF) DO
  527. GetCh();
  528. END;
  529. END GetLine;
  530. (*PROCEDURE Operand(CONST op: ARRAY OF CHAR);
  531. VAR i: LONGINT;
  532. BEGIN
  533. IF op[0] = 0X THEN w.String("none")
  534. ELSIF op = "1" THEN w.String("one")
  535. ELSIF op ="3" THEN w.String("three");
  536. ELSE
  537. i := 0;
  538. WHILE(op[i] # 0X) DO
  539. IF (op[i] # "/") & (op[i] # ":") & (op[i]# "&") THEN
  540. w.Char(op[i]);
  541. END;
  542. INC(i);
  543. END;
  544. END;
  545. END Operand;*)
  546. PROCEDURE AppendCh(VAR s: ARRAY OF CHAR; c: CHAR);
  547. VAR i: LONGINT;
  548. BEGIN
  549. i := 0;
  550. WHILE(s[i] # 0X) DO
  551. INC(i);
  552. END;
  553. s[i] := c; s[i+1] := 0X;
  554. END AppendCh;
  555. PROCEDURE Append(VAR s: ARRAY OF CHAR; CONST a: ARRAY OF CHAR);
  556. BEGIN
  557. Strings.Append(s,a)
  558. END Append;
  559. PROCEDURE Follows(CONST s: ARRAY OF CHAR; VAR i: LONGINT; CONST this: ARRAY OF CHAR): BOOLEAN;
  560. VAR j,k: LONGINT;
  561. BEGIN
  562. j := i; k := 0;
  563. WHILE(s[j] # 0X) & (this[k] # 0X) & (s[j] = this[k]) DO
  564. INC(j); INC(k);
  565. END;
  566. IF this[k] = 0X THEN
  567. i := j;
  568. RETURN TRUE
  569. ELSE
  570. RETURN FALSE
  571. END;
  572. END Follows;
  573. PROCEDURE OpCode(CONST code: ARRAY OF CHAR);
  574. VAR ch: CHAR; i: LONGINT;
  575. op: ARRAY 3 OF CHAR;
  576. nOp: LONGINT;
  577. ModRM:ARRAY 256 OF CHAR; error: BOOLEAN;
  578. opCodeExtension: LONGINT;
  579. length: LONGINT;
  580. PROCEDURE NextOption(VAR s: ARRAY OF CHAR);
  581. BEGIN
  582. IF s[0] # 0X THEN Append(s,",") END;
  583. END NextOption;
  584. PROCEDURE Hex(ch: CHAR): LONGINT;
  585. BEGIN
  586. IF ("0" <= ch) & (ch <= "9") THEN
  587. RETURN ORD(ch)-ORD("0");
  588. ELSIF ("A" <= ch) & (ch <= "F") THEN
  589. RETURN ORD(ch)-ORD("A")+10;
  590. ELSE error := TRUE; RETURN 0
  591. END;
  592. END Hex;
  593. BEGIN
  594. error := FALSE;
  595. ModRM := "";
  596. op[0] := 0X;
  597. op[1] := 0X;
  598. op[2] := 0X;
  599. opCodeExtension := -1;
  600. w.String('"');
  601. i := 0;
  602. nOp := 0;
  603. length := 0;
  604. REPEAT
  605. ch := code[i]; INC(i);
  606. CASE ch OF
  607. 0X:
  608. |" ":
  609. |"0".."9","A".."F":
  610. INC(length,2);
  611. (* options should not occur between opcodes, otherwise the order seems to be important...
  612. the only case where an option occurs between opcodes is for PAVGUSB: /r option which does not affect any order anyway
  613. *)
  614. CASE code[i] OF
  615. "0".."9","A".."F":
  616. w.Char(ch); w.Char(code[i]);
  617. op[nOp] := CHR(16*Hex(ch) + Hex(code[i])); INC(i);
  618. ELSE
  619. w.Char("0"); w.Char(ch);
  620. op[nOp] := CHR(Hex(ch));
  621. END;
  622. INC(nOp);
  623. |"/":
  624. ch := code[i]; INC(i);
  625. NextOption(ModRM);
  626. w.Char("/");
  627. CASE ch OF
  628. "0".."7":
  629. INC(length,2);
  630. w.Char(ch);
  631. Append(ModRM,"modRMExtension");
  632. opCodeExtension := ORD(ch)-ORD("0");
  633. |"r":
  634. INC(length);
  635. w.Char(ch);
  636. Append(ModRM,"modRMBoth");
  637. ELSE error := TRUE
  638. END;
  639. |"c":
  640. INC(length);
  641. ch := code[i]; INC(i);
  642. NextOption(ModRM);
  643. CASE ch OF
  644. "b","w","d","p": Append(ModRM,"c"); AppendCh(ModRM,ch); w.Char("c"); w.Char(ch);
  645. ELSE error := TRUE
  646. END;
  647. |"i":
  648. INC(length);
  649. ch := code[i]; INC(i);
  650. NextOption(ModRM);
  651. CASE ch OF
  652. "b","w","d","q": Append(ModRM,"i"); AppendCh(ModRM,ch);
  653. w.Char("i"); w.Char(ch);
  654. ELSE error := TRUE
  655. END;
  656. |"m":
  657. INC(length);
  658. NextOption(ModRM);
  659. IF Follows(code,i,"64") THEN
  660. Append(ModRM,"mem64Operand");
  661. w.String("m6");
  662. ELSIF Follows(code,i,"128") THEN
  663. Append(ModRM,"mem128Operand");
  664. w.String("m1");
  665. ELSE error := TRUE
  666. END;
  667. |"+":
  668. INC(length);
  669. ch := code[i]; INC(i);
  670. NextOption(ModRM);
  671. CASE ch OF
  672. 'i': Append(ModRM,"fpStackOperand");
  673. w.String("+i");
  674. |'o': Append(ModRM,"directMemoryOffset");
  675. w.String("+o");
  676. |'r': Append(ModRM,"r");
  677. ch := code[i]; INC(i);
  678. CASE ch OF
  679. 'b','w','d','q': AppendCh(ModRM,ch); w.Char("r"); w.Char(ch);
  680. ELSE w.String(" ERROR IN "); w.String(code); w.Update; HALT(100);
  681. END;
  682. ELSE error := TRUE
  683. END;
  684. ELSE
  685. error := TRUE
  686. END
  687. UNTIL error OR (ch = 0X);
  688. IF error THEN w.String(" ERROR IN "); w.String(code); w.String("at"); w.Int(i,1); w.Update; HALT(100); END;
  689. w.String('"');
  690. INC(length);
  691. IF length > maxOpcodeLength THEN
  692. maxOpcodeLength := length;
  693. END;
  694. (*
  695. w.Int(nOp,1);
  696. w.String(",");
  697. w.Hex(ORD(op[0]),1); w.String("X");
  698. w.String(",");
  699. w.Hex(ORD(op[1]),1); w.String("X");
  700. w.String(",");
  701. w.Hex(ORD(op[2]),1); w.String("X");
  702. w.String(",{");
  703. w.String(ModRM);
  704. w.String("}");
  705. w.String(", ");
  706. w.Int(opCodeExtension,1);
  707. *)
  708. END OpCode;
  709. PROCEDURE Options(CONST prefix,options: ARRAY OF CHAR);
  710. VAR i: LONGINT; first: BOOLEAN;
  711. PROCEDURE NextOptions;
  712. BEGIN
  713. WHILE(options[i] = ",") DO INC(i) END;
  714. IF options[i] = 0X THEN RETURN END;
  715. IF first THEN first := FALSE ELSE w.String(",") END;
  716. w.String(prefix);
  717. WHILE (options[i] # ",") & (options[i] # 0X) DO
  718. w.Char(options[i]);
  719. INC(i);
  720. END;
  721. END NextOptions;
  722. BEGIN
  723. i := 0;
  724. w.String("{");first := TRUE;
  725. WHILE(options[i] # 0X) DO
  726. NextOptions()
  727. END;
  728. w.String("}");
  729. END Options;
  730. PROCEDURE ParseLine(CONST line: ARRAY OF CHAR);
  731. VAR ch: CHAR; i : LONGINT;
  732. PROCEDURE NextSym(VAR sym: ARRAY OF CHAR);
  733. VAR len: LONGINT;
  734. BEGIN
  735. len := 0;
  736. ch:= line[i]; INC(i);
  737. WHILE(ch # TAB) & (ch # LF) & (ch # 0X) DO
  738. WHILE (ch = " ") DO ch:= line[i]; INC(i); END;
  739. sym[len] := ch; INC(len);
  740. ch:= line[i]; INC(i);
  741. END;
  742. sym[len] := 0X;
  743. END NextSym;
  744. BEGIN
  745. i := 0; ch := line[0];
  746. IF (ch = '"') OR (ch = ";") THEN (* comment line skipped *)
  747. ELSE
  748. NextSym(instr);
  749. IF instr = "" THEN
  750. ELSE
  751. mnemonic := firstMnemonic; prevmnemonic := NIL;
  752. WHILE(mnemonic # NIL) & (mnemonic.name < instr) DO
  753. prevmnemonic := mnemonic;
  754. mnemonic := mnemonic.next;
  755. END;
  756. IF (mnemonic = NIL) OR (mnemonic.name # instr) THEN
  757. NEW(mnemonic);
  758. COPY(instr,mnemonic.name);
  759. IF prevmnemonic = NIL THEN
  760. mnemonic.next := firstMnemonic;
  761. firstMnemonic := mnemonic;
  762. ELSE
  763. mnemonic.next := prevmnemonic.next;
  764. prevmnemonic.next := mnemonic;
  765. END;
  766. END;
  767. NEW(instruction);
  768. IF mnemonic.lastInstruction = NIL THEN
  769. mnemonic.lastInstruction := instruction;
  770. mnemonic.firstInstruction := instruction;
  771. ELSE
  772. mnemonic.lastInstruction.next := instruction;
  773. mnemonic.lastInstruction := instruction;
  774. END;
  775. NextSym(instruction.op1);
  776. NextSym(instruction.op2);
  777. NextSym(instruction.op3);
  778. NextSym(instruction.opcode);
  779. NextSym(instruction.target);
  780. NextSym(instruction.bitwidth);
  781. END;
  782. END;
  783. END ParseLine;
  784. BEGIN
  785. context.arg.SkipWhitespace; context.arg.String(fileName);
  786. context.out.String("parsing file "); context.out.String(fileName); context.out.Ln;
  787. IF fileName # "" THEN
  788. NEW(operandReplacer);
  789. operandReplacer.Add ("reg/mem8", "regmem8");
  790. operandReplacer.Add ("reg/mem16", "regmem16");
  791. operandReplacer.Add ("reg/mem32", "regmem32");
  792. operandReplacer.Add ("reg/mem64", "regmem64");
  793. operandReplacer.Add ("mem14/28env", "mem");
  794. operandReplacer.Add ("mem16&mem16", "mem");
  795. operandReplacer.Add ("mem32&mem32", "mem");
  796. operandReplacer.Add ("mem16:16", "mem");
  797. operandReplacer.Add ("mem16:32", "mem");
  798. operandReplacer.Add ("mem16:64", "mem");
  799. operandReplacer.Add ("mem512env", "mem");
  800. operandReplacer.Add ("mem80dec", "mem");
  801. operandReplacer.Add ("mem80real", "mem");
  802. operandReplacer.Add ("mem94/108env", "mem");
  803. operandReplacer.Add ("mem2env", "mem16");
  804. operandReplacer.Add ("xmm1", "xmm");
  805. operandReplacer.Add ("xmm2", "xmm");
  806. operandReplacer.Add ("xmm/mem", "xmmmem");
  807. operandReplacer.Add ("xmm/mem32", "xmmmem32");
  808. operandReplacer.Add ("xmm/mem64", "xmmmem64");
  809. operandReplacer.Add ("xmm/mem128", "xmmmem128");
  810. operandReplacer.Add ("xmm1/mem32", "xmmmem32");
  811. operandReplacer.Add ("xmm1/mem64", "xmmmem64");
  812. operandReplacer.Add ("xmm1/mem128", "xmmmem128");
  813. operandReplacer.Add ("xmm2/mem32", "xmmmem32");
  814. operandReplacer.Add ("xmm2/mem64", "xmmmem64");
  815. operandReplacer.Add ("xmm2/mem128", "xmmmem128");
  816. operandReplacer.Add ("mmx/mem64", "mmxmem64");
  817. operandReplacer.Add ("mmx1", "mmx");
  818. operandReplacer.Add ("mmx2", "mmx");
  819. operandReplacer.Add ("mmx1/mem64", "mmxmem64");
  820. operandReplacer.Add ("mmx2/mem32", "mmxmem32");
  821. operandReplacer.Add ("mmx2/mem64", "mmxmem64");
  822. operandReplacer.Add ("pntr16:16", "pntr1616");
  823. operandReplacer.Add ("pntr16:32", "pntr1632");
  824. operandReplacer.Add ("mem16int", "mem16");
  825. operandReplacer.Add ("mem32int", "mem32");
  826. operandReplacer.Add ("mem32real", "mem32");
  827. operandReplacer.Add ("mem64int", "mem64");
  828. operandReplacer.Add ("mem64real", "mem64");
  829. (* operandReplacer.Add ("rel8off", "imm");
  830. operandReplacer.Add ("rel16off", "imm");
  831. operandReplacer.Add ("rel32off", "imm");
  832. *)
  833. operandReplacer.Add ("ST(0)", "st0");
  834. operandReplacer.Add ("ST(i)", "sti");
  835. NEW(cpuoptionReplacer);
  836. cpuoptionReplacer.Add ("KATMAI", "Katmai");
  837. cpuoptionReplacer.Add ("PRESCOTT", "Prescott");
  838. cpuoptionReplacer.Add ("WILLAMETTE", "Willamette");
  839. cpuoptionReplacer.Add ("PENTIUM", "Pentium");
  840. cpuoptionReplacer.Add ("3DNOW", "3DNow");
  841. cpuoptionReplacer.Add ("PRIV", "Privileged");
  842. cpuoptionReplacer.Add ("PROT", "Protected");
  843. cpuoptionReplacer.Add ("SW","");
  844. cpuoptionReplacer.Add ("SB","");
  845. cpuoptionReplacer.Add ("SMM","");
  846. cpuoptionReplacer.Add ("AR1","");
  847. cpuoptionReplacer.Add ("AR2","");
  848. cpuoptionReplacer.Add ("ND","");
  849. NEW(bitwidthReplacer);
  850. bitwidthReplacer.Add("INV","I64");
  851. file := Files.Old(fileName);
  852. NEW(reader,file,0);
  853. GetCh();
  854. WHILE(ch # 0X) DO
  855. GetLine(line);
  856. ParseLine(line);
  857. END;
  858. w := context.out;
  859. numberMnemonics := 0;
  860. numberInstructions := 0;
  861. maxMnemonicNameLength := 0;
  862. mnemonic := firstMnemonic;
  863. WHILE (mnemonic # NIL) DO
  864. w.Char(09X); w.Char(09X); w.String("AddMnemonic(");
  865. w.String("op");
  866. w.String(mnemonic.name);
  867. w.String(", ");
  868. w.Char('"');
  869. w.String(mnemonic.name);
  870. w.Char('"');
  871. (*w.String(", ");
  872. w.Int(numberInstructions,1);
  873. *)
  874. w.String(");");
  875. w.Ln;
  876. mnemonic := mnemonic.next;
  877. END;
  878. mnemonic := firstMnemonic;
  879. maxOpcodeLength:= 0;
  880. WHILE(mnemonic # NIL) DO
  881. (*
  882. IF Strings.Length(mnemonic.name)+1 > maxMnemonicNameLength THEN maxMnemonicNameLength := Strings.Length(mnemonic.name)+1 END;
  883. w.Char(09X); w.Char(09X); w.String("StartMnemonic(");
  884. w.String("op");
  885. w.String(mnemonic.name);
  886. w.String(", ");
  887. w.Char('"');
  888. w.String(mnemonic.name);
  889. w.Char('"');
  890. (*w.String(", ");
  891. w.Int(numberInstructions,1);
  892. *)
  893. w.String(");");
  894. w.Ln;
  895. INC(numberMnemonics);
  896. *)
  897. instruction := mnemonic.firstInstruction;
  898. WHILE(instruction # NIL) DO
  899. (*
  900. operandReplacer.Do(instruction.op1);
  901. operandReplacer.Do(instruction.op2);
  902. operandReplacer.Do(instruction.op3);
  903. *)
  904. bitwidthReplacer.Do(instruction.bitwidth);
  905. cpuoptionReplacer.Do(instruction.target);
  906. instruction := instruction.next;
  907. END;
  908. SortInstructions(mnemonic.firstInstruction);
  909. instruction := mnemonic.firstInstruction;
  910. WHILE(instruction # NIL) DO
  911. w.Char(09X); w.Char(09X);
  912. w.String("AddInstruction(");
  913. w.String("op");
  914. w.String(mnemonic.name);
  915. w.String(", ");
  916. w.String('"');
  917. w.String(instruction.op1);
  918. IF instruction.op2 # "" THEN
  919. w.String(",");
  920. w.String(instruction.op2);
  921. END;
  922. IF instruction.op3 # "" THEN
  923. ASSERT(instruction.op2 # "");
  924. w.String(",");
  925. w.String(instruction.op3);
  926. END;
  927. w.String('", ');
  928. OpCode(instruction.opcode); w.String(", ");
  929. Options("opt",instruction.bitwidth); w.String(", ");
  930. Options("cpu",instruction.target); w.String(");");
  931. (*
  932. w.String('", "');
  933. w.String(instruction.bitwidth);
  934. w.String('", "');
  935. w.String(instruction.target);
  936. w.String('"');*)
  937. w.Ln;
  938. (*
  939. w.Int(numberInstructions,1); w.String(", ");
  940. Operand(instruction.op1); w.String(", ");
  941. Operand(instruction.op2); w.String(", ");
  942. Operand(instruction.op3); w.String(", ");
  943. OpCode(instruction.opcode); w.String(", ");
  944. Options("opt",instruction.bitwidth); w.String(", ");
  945. Options("cpu",instruction.target); w.String(");");
  946. w.Ln;
  947. INC(numberInstructions);
  948. *)
  949. instruction := instruction.next;
  950. END;
  951. (*
  952. w.Char(09X); w.Char(09X); w.String("EndMnemonic(");
  953. w.String("op"); w.String(mnemonic.name);
  954. w.String(", ");
  955. w.Int(numberInstructions-1,1);
  956. w.String(");");
  957. *)
  958. (*
  959. w.Ln;
  960. *)
  961. mnemonic := mnemonic.next;
  962. END;
  963. w.Char(09X); w.String("numberMnemonics = "); w.Int(numberMnemonics,1); w.String(";"); w.Ln;
  964. w.Char(09X); w.String("numberInstructions = "); w.Int(numberInstructions,1); w.String(";");w.Ln;
  965. w.Char(09X); w.String("maxMnemonicNameLength ="); w.Int(maxMnemonicNameLength,1); w.String(";"); w.Ln;
  966. w.Char(09X); w.String("maxCodeLength* ="); w.Int(maxOpcodeLength,1); w.String(";"); w.Ln;
  967. mnemonic := firstMnemonic; numberMnemonics := 0;
  968. WHILE(mnemonic # NIL) DO
  969. w.Char(09X); w.String("op"); w.String(mnemonic.name);
  970. w.String("*,");
  971. (* w.Int(numberMnemonics,1); w.String(";");*)
  972. w.Ln;
  973. INC(numberMnemonics);
  974. mnemonic := mnemonic.next;
  975. END;
  976. w.Update;
  977. context.out.String("done"); context.out.Ln;
  978. ELSE
  979. context.error.String("filename expected"); context.error.Ln;
  980. END;
  981. END ParseAMDInstructionSet;
  982. END FoxProgTools.
  983. System.Free FoxProgTools ~
  984. FoxProgTools.Enum -l=2 a b c (* test (* test *) *) d e f g h i j k (* ddd *) d d d ~
  985. FoxProgTools.Enum --incremental a b c d e ~
  986. FoxProgTools.Enum --start=10 a b c d e ~
  987. FoxProgTools.Enum --start=10 --hex a b c d e ~
  988. FoxProgTools.ParseAMDInstructionSet FoxInstructionSetAMD64TabSeperated.txt ~
  989. FoxProgTools.ParseARMInstructionSet OC/FoxInstructionSetARM.txt ~