ldscript.pas 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. {
  2. Copyright (c) 2012 by Sergei Gorelkin
  3. A basic lexer for GNU ld scripts
  4. This program is free software; you can redistribute it and/or modify
  5. iu under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge- MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit ldscript;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. owbase;
  22. type
  23. TldScriptToken=char;
  24. TScriptLexer=class(TObject)
  25. data: ansistring;
  26. curtoken: TldScriptToken;
  27. curtokenstr: string;
  28. curpos: longint;
  29. line: longint;
  30. linestart: longint;
  31. public
  32. constructor Create(aReader:TObjectReader);
  33. procedure nextToken;
  34. function CheckForIdent(const s:string):boolean;
  35. function CheckFor(c:TldScriptToken):boolean;
  36. procedure Expect(c:TldScriptToken);
  37. property token:TldScriptToken read curtoken;
  38. property tokenstr:string read curtokenstr;
  39. end;
  40. const
  41. tkEOF = #0;
  42. tkINVALID = #1;
  43. tkIDENT = #2;
  44. tkNUMBER = #3;
  45. tkLITERAL = #4;
  46. tkLSHIFT = #5; { << }
  47. tkLE = #6; { <= }
  48. tkRSHIFT = #7; { >> }
  49. tkGE = #8; { >= }
  50. tkANDAND = #9; { && }
  51. tkANDEQ = #10; { &= }
  52. tkOROR = #11; { || }
  53. tkOREQ = #12; { |= }
  54. tkDIVEQ = #13; { /= }
  55. tkMULTEQ = #14; { *= }
  56. tkMINUSEQ = #15; { -= }
  57. tkPLUSEQ = #16; { += }
  58. tkNE = #17; { != }
  59. tkEQ = #18; { == }
  60. tkRSHIFTEQ = #19; { >>= }
  61. tkLSHIFTEQ = #20; { <<= }
  62. implementation
  63. uses
  64. sysutils;
  65. const
  66. NameChars=['A'..'Z','a'..'z','_','.','$','0'..'9','+','-','=',',','*','?','/','~','\','[',']'];
  67. {*****************************************************************************
  68. TSCRIPTLEXER
  69. *****************************************************************************}
  70. constructor TScriptLexer.Create(AReader:TObjectReader);
  71. begin
  72. { Expected data size is few hundred bytes, }
  73. SetLength(data,AReader.size);
  74. AReader.Read(data[1],AReader.size);
  75. curpos:=1;
  76. end;
  77. procedure TScriptLexer.nextToken;
  78. var
  79. p,start: longint;
  80. begin
  81. p:=curpos;
  82. repeat
  83. { skip whitespace }
  84. while (data[p] in [#32,#9,#13]) do
  85. inc(p);
  86. start:=p;
  87. { C-style comment }
  88. if (data[p]='/') and (data[p+1]='*') then
  89. begin
  90. inc(p,2);
  91. while (data[p]<>'*') and (data[p+1]<>'/') do
  92. begin
  93. if (data[p]=#0) then
  94. begin
  95. curtoken:=tkINVALID;
  96. exit;
  97. end;
  98. if (data[p]=#10) then
  99. begin
  100. inc(line);
  101. linestart:=p+1;
  102. end;
  103. inc(p);
  104. end;
  105. inc(p,2);
  106. continue;
  107. end
  108. else if (data[p]=#10) then
  109. begin
  110. inc(p);
  111. inc(line);
  112. linestart:=p;
  113. continue;
  114. end
  115. else if (data[p]='#') then { line comment }
  116. begin
  117. inc(p);
  118. while (data[p]<>#0) and (data[p]<>#10) do
  119. inc(p);
  120. continue;
  121. end;
  122. case data[p] of
  123. #0: curtoken:=tkEOF;
  124. '/':
  125. if (data[p+1] in NameChars) then
  126. begin
  127. inc(p);
  128. while (data[p] in NameChars) do
  129. inc(p);
  130. curtoken:=tkIDENT;
  131. end
  132. else if (data[p+1]='=') then
  133. curtoken:=tkDIVEQ
  134. else
  135. curtoken:='/';
  136. 'A'..'Z','a'..'z','_','.','$','\':
  137. begin
  138. inc(p);
  139. while (data[p] in NameChars) do
  140. inc(p);
  141. curtoken:=tkIDENT;
  142. end;
  143. '0'..'9':
  144. begin
  145. if (data[p]='0') and (data[p+1] in ['x','X']) then
  146. begin
  147. inc(p,2);
  148. while data[p] in ['0'..'9','a'..'f','A'..'F'] do
  149. inc(p);
  150. end
  151. else
  152. while (data[p] in ['0'..'9']) do
  153. inc(p);
  154. curtoken:=tkNUMBER;
  155. end;
  156. '"':
  157. begin
  158. inc(p);
  159. while (data[p]<>'"') and (data[p]<>#10) do
  160. inc(p);
  161. if data[p]=#10 then
  162. begin
  163. curtoken:=tkINVALID;
  164. exit;
  165. end;
  166. inc(p);
  167. curtoken:=tkLITERAL;
  168. end;
  169. '<':
  170. if (data[p+1]='<') then
  171. begin
  172. if (data[p+2]='=') then
  173. curtoken:=tkLSHIFTEQ
  174. else
  175. curtoken:=tkLSHIFT;
  176. end
  177. else if (data[p+1]='=') then
  178. curtoken:=tkLE
  179. else
  180. curtoken:='<';
  181. '>':
  182. if (data[p+1]='>') then
  183. begin
  184. if (data[p+2]='=') then
  185. curtoken:=tkRSHIFTEQ
  186. else
  187. curtoken:=tkRSHIFT;
  188. end
  189. else if (data[p+1]='=') then
  190. curtoken:=tkGE
  191. else
  192. curtoken:='>';
  193. '!':
  194. if (data[p+1]='=') then
  195. curtoken:=tkNE
  196. else
  197. curtoken:='!';
  198. '&':
  199. if (data[p+1]='&') then
  200. curtoken:=tkANDAND
  201. else if (data[p+1]='=') then
  202. curtoken:=tkANDEQ
  203. else
  204. curtoken:='&';
  205. '|':
  206. if (data[p+1]='|') then
  207. curtoken:=tkOROR
  208. else if (data[p+1]='=') then
  209. curtoken:=tkOREQ
  210. else
  211. curtoken:='|';
  212. '*':
  213. if (data[p+1]='=') then
  214. curtoken:=tkMULTEQ
  215. else
  216. curtoken:='*';
  217. '+':
  218. if (data[p+1]='=') then
  219. curtoken:=tkPLUSEQ
  220. else
  221. curtoken:='+';
  222. '-':
  223. if (data[p+1]='=') then
  224. curtoken:=tkMINUSEQ
  225. else
  226. curtoken:='-';
  227. '=':
  228. if (data[p+1]='=') then
  229. curtoken:=tkEQ
  230. else
  231. curtoken:='=';
  232. '(',')','{','}','[',']',';','?',':':
  233. curtoken:=data[p];
  234. else
  235. curtoken:=tkINVALID;
  236. exit;
  237. end;
  238. break;
  239. until false;
  240. case curtoken of
  241. tkRSHIFTEQ,tkLSHIFTEQ: inc(p,3);
  242. tkLSHIFT..tkEQ: inc(p,2);
  243. #32..#255: inc(p);
  244. tkIDENT,tkNUMBER:
  245. setstring(curtokenstr,PChar(@data[start]),p-start);
  246. tkLITERAL:
  247. setstring(curtokenstr,PChar(@data[start+1]),p-start-2);
  248. end;
  249. curpos:=p;
  250. end;
  251. procedure TScriptLexer.Expect(c:TldScriptToken);
  252. begin
  253. if (curtoken=c) then
  254. nextToken
  255. else
  256. {error};
  257. end;
  258. function TScriptLexer.CheckForIdent(const s:string):boolean;
  259. begin
  260. result:=(curtoken=tkIDENT) and (curtokenstr=s);
  261. if result then
  262. nextToken;
  263. end;
  264. function TScriptLexer.CheckFor(c:TldScriptToken):boolean;
  265. begin
  266. result:=(curtoken=c);
  267. if result then
  268. nextToken;
  269. end;
  270. end.