CSS2Parser.Mod 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. MODULE CSS2Parser; (** Stefan Walthert *)
  2. (** AUTHOR "swalthert"; PURPOSE ""; *)
  3. IMPORT
  4. KernelLog, Strings, Scanner := CSS2Scanner, XMLObjects, CSS2, Files;
  5. TYPE
  6. String = CSS2.String;
  7. Parser* = OBJECT
  8. VAR
  9. reportError*: PROCEDURE(pos, line, row: LONGINT; msg: ARRAY OF CHAR);
  10. scanner: Scanner.Scanner;
  11. PROCEDURE & Init*(scanner: Scanner.Scanner);
  12. BEGIN
  13. reportError := DefaultReportError;
  14. SELF.scanner := scanner;
  15. scanner.Scan()
  16. END Init;
  17. PROCEDURE CheckSymbol(expectedSymbols: SET; errormsg: ARRAY OF CHAR): BOOLEAN;
  18. BEGIN
  19. IF scanner.sym IN expectedSymbols THEN
  20. RETURN TRUE
  21. ELSE
  22. Error(errormsg);
  23. RETURN FALSE
  24. END
  25. END CheckSymbol;
  26. PROCEDURE Error(msg: ARRAY OF CHAR);
  27. BEGIN
  28. reportError(scanner.GetPos(), scanner.line, scanner.row, msg)
  29. END Error;
  30. PROCEDURE Parse*(): CSS2.StyleSheet;
  31. VAR styleSheet: CSS2.StyleSheet; s: String;
  32. BEGIN
  33. NEW(styleSheet);
  34. s := scanner.GetStr();
  35. IF (scanner.sym = Scanner.AtKeyword) & (s^ = 'charset') THEN
  36. scanner.Scan();
  37. IF ~CheckSymbol({Scanner.String}, "charset expected") THEN RETURN styleSheet END;
  38. s := scanner.GetStr(); styleSheet.SetCharSet(s^);
  39. scanner.Scan();
  40. IF ~CheckSymbol({Scanner.Semicolon}, "';' expected") THEN RETURN styleSheet END;
  41. scanner.Scan()
  42. END;
  43. WHILE scanner.sym IN {Scanner.Cdo, Scanner.Cdc} DO scanner.Scan() END;
  44. s := scanner.GetStr();
  45. WHILE (scanner.sym = Scanner.AtKeyword) & (s^ = 'import') DO
  46. ParseImport(styleSheet);
  47. s := scanner.GetStr()
  48. END;
  49. WHILE scanner.sym # Scanner.Eof DO
  50. IF scanner.sym = Scanner.AtKeyword THEN
  51. s := scanner.GetStr();
  52. IF s^ = 'media' THEN
  53. ParseMedia(styleSheet)
  54. ELSIF s^ = 'page' THEN
  55. styleSheet.AddPage(ParsePage())
  56. ELSIF s^ = 'font-face' THEN
  57. styleSheet.AddFontFace(ParseFontFace())
  58. ELSE (* skip unknown atkeyword *)
  59. IgnoreKeyword()
  60. END
  61. ELSIF scanner.sym # Scanner.Eof THEN
  62. styleSheet.AddRuleSet(ParseRuleSet())
  63. END;
  64. WHILE scanner.sym IN {Scanner.Cdo, Scanner.Cdc} DO scanner.Scan() END
  65. END;
  66. RETURN styleSheet
  67. END Parse;
  68. PROCEDURE ParseImport(styleSheet: CSS2.StyleSheet);
  69. VAR s: String; newParser: Parser; newScanner: Scanner.Scanner; file: Files.File;
  70. importedStyleSheet: CSS2.StyleSheet; media, media2, media3: SET; ruleSets: XMLObjects.Enumerator;
  71. ruleSet: ANY;
  72. BEGIN
  73. scanner.Scan();
  74. IF ~CheckSymbol({Scanner.String, Scanner.URI}, "URI expected") THEN RETURN END;
  75. s := scanner.GetStr();
  76. file := Files.Old(s^);
  77. IF file # NIL THEN
  78. NEW(newScanner, file);
  79. NEW(newParser, newScanner); newParser.reportError := reportError;
  80. importedStyleSheet := newParser.Parse()
  81. END;
  82. scanner.Scan();
  83. IF scanner.sym # Scanner.Ident THEN
  84. INCL(media, CSS2.All)
  85. ELSE
  86. s := scanner.GetStr();
  87. INCL(media, GetMedium(s^));
  88. scanner.Scan();
  89. WHILE scanner.sym = Scanner.Comma DO
  90. scanner.Scan();
  91. IF ~CheckSymbol({Scanner.Ident}, "medium identifier expected") THEN RETURN END;
  92. s := scanner.GetStr();
  93. INCL(media, GetMedium(s^));
  94. scanner.Scan()
  95. END
  96. END;
  97. ruleSets := importedStyleSheet.GetRuleSets();
  98. WHILE ruleSets.HasMoreElements() DO
  99. ruleSet := ruleSets.GetNext();
  100. media2 := ruleSet(CSS2.RuleSet).GetMedia();
  101. media3 := media + media2;
  102. IF (media3 - {CSS2.All} # {}) THEN media3 := media3 - {CSS2.All} END;
  103. ruleSet(CSS2.RuleSet).SetMedia(media3);
  104. styleSheet.AddRuleSet(ruleSet(CSS2.RuleSet))
  105. END;
  106. IF ~CheckSymbol({Scanner.Semicolon}, "';' expected") THEN RETURN END;
  107. scanner.Scan()
  108. END ParseImport;
  109. PROCEDURE ParseMedia(styleSheet: CSS2.StyleSheet);
  110. VAR s: String; media: SET; ruleSet: CSS2.RuleSet;
  111. BEGIN
  112. scanner.Scan();
  113. IF ~CheckSymbol({Scanner.Ident}, "medium identifier expected") THEN RETURN END;
  114. s := scanner.GetStr();
  115. INCL(media, GetMedium(s^));
  116. scanner.Scan();
  117. WHILE scanner.sym = Scanner.Comma DO
  118. scanner.Scan();
  119. IF ~CheckSymbol({Scanner.Ident}, "medium identifier expected") THEN RETURN END;
  120. s := scanner.GetStr();
  121. INCL(media, GetMedium(s^));
  122. scanner.Scan()
  123. END;
  124. IF ~CheckSymbol({Scanner.BraceOpen}, "'{' expected") THEN RETURN END;
  125. scanner.Scan();
  126. WHILE (scanner.sym # Scanner.BraceClose) & (scanner.sym # Scanner.Eof) & (scanner.sym # Scanner.Invalid) DO
  127. ruleSet := ParseRuleSet();
  128. ruleSet.SetMedia(media);
  129. styleSheet.AddRuleSet(ruleSet)
  130. END;
  131. IF ~CheckSymbol({Scanner.BraceClose}, "'}' expected") THEN RETURN END;
  132. scanner.Scan()
  133. END ParseMedia;
  134. PROCEDURE ParsePage(): CSS2.Page;
  135. VAR page: CSS2.Page; s: String;
  136. BEGIN
  137. scanner.Scan();
  138. IF ~CheckSymbol({Scanner.Ident, Scanner.Colon, Scanner.BraceOpen},
  139. "page selector, pseudo page or '{' expected") THEN RETURN page END;
  140. NEW(page);
  141. IF scanner.sym = Scanner.Ident THEN
  142. s := scanner.GetStr();
  143. page.SetSelector(s^);
  144. scanner.Scan()
  145. END;
  146. IF ~CheckSymbol({Scanner.Colon, Scanner.BraceOpen}, "pseudo page or '{' expected") THEN RETURN page END;
  147. IF scanner.sym = Scanner.Colon THEN
  148. scanner.Scan();
  149. IF ~CheckSymbol({Scanner.Ident}, "pseudo page identifier expected") THEN RETURN page END;
  150. s := scanner.GetStr();
  151. page.SetPseudoPage(GetPseudoPage(s^));
  152. scanner.Scan()
  153. END;
  154. IF ~CheckSymbol({Scanner.BraceOpen}, "'{' expected") THEN RETURN page END;
  155. scanner.Scan();
  156. page.AddDeclaration(ParseDeclaration());
  157. WHILE scanner.sym = Scanner.Semicolon DO
  158. scanner.Scan();
  159. page.AddDeclaration(ParseDeclaration());
  160. END;
  161. IF ~CheckSymbol({Scanner.BraceClose}, "'}' expected") THEN RETURN page END;
  162. scanner.Scan();
  163. RETURN page
  164. END ParsePage;
  165. PROCEDURE ParseFontFace(): CSS2.FontFace;
  166. VAR fontFace: CSS2.FontFace;
  167. BEGIN
  168. scanner.Scan();
  169. IF ~CheckSymbol({Scanner.BraceOpen}, "'{' expected") THEN RETURN fontFace END;
  170. NEW(fontFace);
  171. scanner.Scan();
  172. fontFace.AddDeclaration(ParseDeclaration());
  173. WHILE scanner.sym = Scanner.Semicolon DO
  174. scanner.Scan();
  175. fontFace.AddDeclaration(ParseDeclaration());
  176. END;
  177. IF ~CheckSymbol({Scanner.BraceClose}, "'}' expected") THEN RETURN fontFace END;
  178. scanner.Scan();
  179. RETURN fontFace
  180. END ParseFontFace;
  181. PROCEDURE ParseRuleSet(): CSS2.RuleSet;
  182. VAR ruleSet: CSS2.RuleSet;
  183. BEGIN
  184. NEW(ruleSet);
  185. ruleSet.AddSelector(ParseSelector());
  186. WHILE scanner.sym = Scanner.Comma DO
  187. scanner.Scan();
  188. ruleSet.AddSelector(ParseSelector())
  189. END;
  190. IF ~CheckSymbol({Scanner.BraceOpen}, "'{' expected") THEN RETURN ruleSet END;
  191. scanner.Scan();
  192. ruleSet.AddDeclaration(ParseDeclaration());
  193. WHILE scanner.sym = Scanner.Semicolon DO
  194. scanner.Scan();
  195. IF scanner.sym # Scanner.BraceClose THEN ruleSet.AddDeclaration(ParseDeclaration()) END
  196. END;
  197. IF ~CheckSymbol({Scanner.BraceClose}, "'}' expected") THEN RETURN ruleSet END;
  198. scanner.Scan();
  199. RETURN ruleSet
  200. END ParseRuleSet;
  201. PROCEDURE ParseSelector(): CSS2.Selector;
  202. VAR selector: CSS2.Selector;
  203. BEGIN
  204. NEW(selector);
  205. selector.AddSimpleSelector(ParseSimpleSelector());
  206. WHILE scanner.sym IN {Scanner.Ident, Scanner.Asterisk, Scanner.Hash, Scanner.Dot, Scanner.BracketOpen,
  207. Scanner.Colon, Scanner.Greater, Scanner.Plus} DO
  208. selector.AddSimpleSelector(ParseSimpleSelector())
  209. END;
  210. RETURN selector
  211. END ParseSelector;
  212. PROCEDURE ParseSimpleSelector(): CSS2.SimpleSelector;
  213. VAR simpleSelector: CSS2.SimpleSelector; s: String;
  214. BEGIN
  215. NEW(simpleSelector);
  216. IF scanner.sym = Scanner.Plus THEN
  217. simpleSelector.SetCombinator(CSS2.Sibling); scanner.Scan()
  218. ELSIF scanner.sym = Scanner.Greater THEN
  219. simpleSelector.SetCombinator(CSS2.Child); scanner.Scan()
  220. ELSE
  221. simpleSelector.SetCombinator(CSS2.Descendant)
  222. END;
  223. IF scanner.sym = Scanner.Ident THEN
  224. s := scanner.GetStr();
  225. simpleSelector.SetElementName(s^); scanner.Scan()
  226. ELSE
  227. NEW(s, 2); s[0] := '*'; s[1] := 0X;
  228. simpleSelector.SetElementName(s^);
  229. IF scanner.sym = Scanner.Asterisk THEN scanner.Scan() END
  230. END;
  231. WHILE scanner.sym IN {Scanner.Hash, Scanner.Dot, Scanner.BracketOpen, Scanner.Colon} DO
  232. CASE scanner.sym OF
  233. | Scanner.Hash: simpleSelector.AddSubSelector(ParseId())
  234. | Scanner.Dot: simpleSelector.AddSubSelector(ParseClass())
  235. | Scanner.BracketOpen: simpleSelector.AddSubSelector(ParseAttribute())
  236. | Scanner.Colon: simpleSelector.AddSubSelector(ParsePseudo())
  237. ELSE (* do nothing *)
  238. END
  239. END;
  240. RETURN simpleSelector
  241. END ParseSimpleSelector;
  242. PROCEDURE ParseId(): CSS2.Id;
  243. VAR id: CSS2.Id; s: String;
  244. BEGIN
  245. IF ~CheckSymbol({Scanner.Hash}, "'#'element id expected") THEN RETURN id END;
  246. NEW(id);
  247. s := scanner.GetStr();
  248. id.SetValue(s^);
  249. scanner.Scan();
  250. RETURN id
  251. END ParseId;
  252. PROCEDURE ParseClass(): CSS2.Class;
  253. VAR class: CSS2.Class; s: String;
  254. BEGIN
  255. IF ~CheckSymbol({Scanner.Dot}, "'.'class value expected") THEN RETURN class END;
  256. scanner.Scan();
  257. IF ~CheckSymbol({Scanner.Ident}, "class value expected") THEN RETURN class END;
  258. NEW(class);
  259. s := scanner.GetStr();
  260. class.SetValue(s^);
  261. scanner.Scan();
  262. RETURN class
  263. END ParseClass;
  264. PROCEDURE ParseAttribute(): CSS2.Attribute;
  265. VAR attribute: CSS2.Attribute; s: String;
  266. BEGIN
  267. IF ~CheckSymbol({Scanner.BracketOpen}, "'[' expected") THEN RETURN attribute END;
  268. scanner.Scan();
  269. IF ~CheckSymbol({Scanner.Ident}, "attribute name expected") THEN RETURN attribute END;
  270. NEW(attribute);
  271. s := scanner.GetStr();
  272. attribute.SetName(s^);
  273. scanner.Scan();
  274. IF scanner.sym IN {Scanner.Equal, Scanner.Includes, Scanner.Dashmatch} THEN
  275. CASE scanner.sym OF
  276. | Scanner.Equal: attribute.SetRelation(CSS2.Equal)
  277. | Scanner.Includes: attribute.SetRelation(CSS2.Includes)
  278. | Scanner.Dashmatch: attribute.SetRelation(CSS2.Dashmatch)
  279. END;
  280. scanner.Scan();
  281. IF ~CheckSymbol({Scanner.Ident, Scanner.String}, "attribute value expected") THEN RETURN attribute END;
  282. s := scanner.GetStr();
  283. attribute.SetValue(s^);
  284. scanner.Scan()
  285. END;
  286. IF ~CheckSymbol({Scanner.BracketClose}, "']' expected") THEN RETURN attribute END;
  287. scanner.Scan();
  288. RETURN attribute
  289. END ParseAttribute;
  290. PROCEDURE ParsePseudo(): CSS2.Pseudo;
  291. VAR pseudo: CSS2.Pseudo; s: String;
  292. BEGIN
  293. IF ~CheckSymbol({Scanner.Colon}, "':' expected") THEN RETURN pseudo END;
  294. scanner.Scan();
  295. IF ~CheckSymbol({Scanner.Ident, Scanner.Function}, "':'type expected") THEN RETURN pseudo END;
  296. s := scanner.GetStr();
  297. NEW(pseudo);
  298. pseudo.SetType(s^);
  299. IF (scanner.sym = Scanner.Function) & (s^ = 'lang') THEN
  300. scanner.Scan();
  301. IF ~CheckSymbol({Scanner.Ident}, "language expected") THEN RETURN pseudo END;
  302. s := scanner.GetStr();
  303. pseudo.SetLanguage(s^);
  304. scanner.Scan();
  305. IF ~CheckSymbol({Scanner.ParenClose}, "')' expected") THEN RETURN pseudo END
  306. END;
  307. scanner.Scan();
  308. RETURN pseudo
  309. END ParsePseudo;
  310. PROCEDURE ParseDeclaration(): CSS2.Declaration;
  311. VAR declaration: CSS2.Declaration; s: String;
  312. BEGIN
  313. IF ~CheckSymbol({Scanner.Ident}, "declaration property expected") THEN RETURN declaration END;
  314. NEW(declaration);
  315. s := scanner.GetStr();
  316. declaration.SetProperty(s^);
  317. scanner.Scan();
  318. IF ~CheckSymbol({Scanner.Colon}, "':' expected") THEN RETURN declaration END;
  319. scanner.Scan();
  320. declaration.AddTerm(ParseTerm());
  321. WHILE ~(scanner.sym IN {Scanner.Semicolon, Scanner.BraceClose, Scanner.Important, Scanner.Eof})
  322. & (scanner.sym # Scanner.Invalid) DO (* expr *)
  323. declaration.AddTerm(ParseTerm())
  324. END;
  325. IF scanner.sym = Scanner.Important THEN
  326. declaration.SetImportant(TRUE);
  327. scanner.Scan()
  328. END;
  329. RETURN declaration
  330. END ParseDeclaration;
  331. PROCEDURE ParseTerm(): CSS2.Term;
  332. VAR term: CSS2.Term; s: String;
  333. BEGIN
  334. NEW(term);
  335. IF scanner.sym = Scanner.Slash THEN
  336. term.SetOperator(CSS2.Slash); scanner.Scan()
  337. ELSIF scanner.sym = Scanner.Comma THEN
  338. term.SetOperator(CSS2.Comma); scanner.Scan()
  339. END;
  340. IF scanner.sym = Scanner.Minus THEN
  341. term.SetUnaryOperator(CSS2.Minus); scanner.Scan()
  342. ELSIF scanner.sym = Scanner.Plus THEN
  343. term.SetUnaryOperator(CSS2.Plus); scanner.Scan()
  344. END;
  345. CASE scanner.sym OF
  346. | Scanner.Number:
  347. IF scanner.numberType = Scanner.Integer THEN
  348. term.SetType(CSS2.IntNumber); term.SetIntVal(scanner.intVal)
  349. ELSIF scanner.numberType = Scanner.Real THEN
  350. term.SetType(CSS2.RealNumber); term.SetRealVal(scanner.realVal)
  351. END
  352. | Scanner.Percentage:
  353. term.SetType(CSS2.Percent);
  354. IF scanner.numberType = Scanner.Integer THEN
  355. term.SetRealVal(scanner.intVal / 100)
  356. ELSIF scanner.numberType = Scanner.Real THEN
  357. term.SetRealVal(scanner.realVal / 100)
  358. END
  359. | Scanner.Dimension:
  360. IF scanner.numberType = Scanner.Integer THEN
  361. term.SetType(CSS2.IntDimension); term.SetIntVal(scanner.intVal)
  362. ELSIF scanner.numberType = Scanner.Real THEN
  363. term.SetType(CSS2.RealDimension); term.SetRealVal(scanner.realVal)
  364. END;
  365. s := scanner.GetStr();
  366. term.SetUnit(GetTermUnit(s^))
  367. | Scanner.Function:
  368. s := scanner.GetStr();
  369. IF (s^ = 'rgb') OR (s^ = 'rgba') THEN
  370. scanner.Scan();
  371. term.SetType(CSS2.Color); term.SetIntVal(ParseRGB(s^ = 'rgba'))
  372. ELSE
  373. term.SetType(CSS2.Function); term.SetStringVal(s^);
  374. scanner.Scan();
  375. term.AddTerm(ParseTerm());
  376. WHILE scanner.sym IN {Scanner.Slash, Scanner.Comma} DO
  377. term.AddTerm(ParseTerm())
  378. END;
  379. IF ~CheckSymbol({Scanner.ParenClose}, "')' expected") THEN RETURN term END;
  380. END
  381. | Scanner.String:
  382. s := scanner.GetStr();
  383. term.SetType(CSS2.StringVal); term.SetStringVal(s^)
  384. | Scanner.Ident:
  385. s := scanner.GetStr();
  386. term.SetType(CSS2.StringIdent); term.SetStringVal(s^)
  387. | Scanner.URI:
  388. s := scanner.GetStr();
  389. term.SetType(CSS2.URI); term.SetStringVal(s^)
  390. (* | Scanner.Unicoderange *)
  391. | Scanner.Hash:
  392. s := scanner.GetStr();
  393. term.SetType(CSS2.Color); term.SetIntVal(ComputeRGB(s^))
  394. ELSE
  395. Error("unknown symbol")
  396. END;
  397. scanner.Scan();
  398. RETURN term
  399. END ParseTerm;
  400. PROCEDURE ParseRGB(hasAlpha: BOOLEAN): LONGINT;
  401. VAR term: CSS2.Term; r, g, b, a: LONGINT;
  402. BEGIN
  403. term := ParseTerm();
  404. IF (term # NIL) & (term.GetOperator() = CSS2.Undefined) & (term.GetUnaryOperator() = CSS2.Plus) THEN
  405. IF (term.GetType() = CSS2.Percent) THEN r := ENTIER(0.5 + term.GetRealVal() * 255)
  406. ELSIF (term.GetType() = CSS2.IntNumber) THEN r := term.GetIntVal()
  407. ELSIF (term.GetType() = CSS2.RealNumber) THEN r := ENTIER(0.5 + term.GetRealVal())
  408. ELSE Error("<number>'%' expected"); RETURN 0
  409. END
  410. ELSE
  411. Error("<number>'%' expected"); RETURN 0
  412. END;
  413. term := ParseTerm();
  414. IF (term # NIL) & (term.GetOperator() = CSS2.Comma) & (term.GetUnaryOperator() = CSS2.Plus) THEN
  415. IF (term.GetType() = CSS2.Percent) THEN g := ENTIER(0.5 + term.GetRealVal() * 255)
  416. ELSIF (term.GetType() = CSS2.IntNumber) THEN g := term.GetIntVal()
  417. ELSIF (term.GetType() = CSS2.RealNumber) THEN g := ENTIER(0.5 + term.GetRealVal())
  418. ELSE Error("<number>'%' expected"); RETURN 0
  419. END
  420. ELSE
  421. Error("<number>'%' expected"); RETURN 0
  422. END;
  423. term := ParseTerm();
  424. IF (term # NIL) & (term.GetOperator() = CSS2.Comma) & (term.GetUnaryOperator() = CSS2.Plus) THEN
  425. IF (term.GetType() = CSS2.Percent) THEN b := ENTIER(0.5 + term.GetRealVal() * 255)
  426. ELSIF (term.GetType() = CSS2.IntNumber) THEN b := term.GetIntVal()
  427. ELSIF (term.GetType() = CSS2.RealNumber) THEN b := ENTIER(0.5 + term.GetRealVal())
  428. ELSE Error("<number>'%' expected"); RETURN 0
  429. END
  430. ELSE
  431. Error("<number>'%' expected"); RETURN 0
  432. END;
  433. IF hasAlpha THEN
  434. term := ParseTerm();
  435. IF (term # NIL) & (term.GetOperator() = CSS2.Comma) & (term.GetUnaryOperator() = CSS2.Plus) THEN
  436. IF (term.GetType() = CSS2.Percent) THEN a := ENTIER(0.5 + term.GetRealVal() * 255)
  437. ELSIF (term.GetType() = CSS2.IntNumber) THEN a := term.GetIntVal()
  438. ELSIF (term.GetType() = CSS2.RealNumber) THEN a := ENTIER(0.5 + term.GetRealVal())
  439. ELSE Error("<number>'%' expected"); RETURN 0
  440. END
  441. END
  442. ELSE
  443. a := 0
  444. END;
  445. IF ~CheckSymbol({Scanner.ParenClose}, "')' expected") THEN RETURN 0 END;
  446. RETURN ASH(a, 24) + ASH(r, 16) + ASH(g, 8) + b
  447. END ParseRGB;
  448. PROCEDURE IgnoreKeyword;
  449. BEGIN
  450. WHILE (scanner.sym # Scanner.BraceOpen) & (scanner.sym # Scanner.Semicolon) & (scanner.sym # Scanner.Eof)
  451. & (scanner.sym # Scanner.Invalid) DO
  452. scanner.Scan();
  453. IF scanner.sym = Scanner.AtKeyword THEN IgnoreKeyword() END
  454. END;
  455. IF ~CheckSymbol({Scanner.BraceOpen, Scanner.Semicolon}, "'{' or ';' expected") THEN RETURN END;
  456. IF scanner.sym = Scanner.BraceOpen THEN
  457. WHILE (scanner.sym # Scanner.BraceClose) & (scanner.sym # Scanner.Eof) & (scanner.sym # Scanner.Invalid) DO
  458. scanner.Scan();
  459. IF scanner.sym = Scanner.AtKeyword THEN IgnoreKeyword() END
  460. END;
  461. IF ~CheckSymbol({Scanner.BraceClose}, "'}' expected") THEN RETURN END
  462. END;
  463. scanner.Scan()
  464. END IgnoreKeyword;
  465. END Parser;
  466. PROCEDURE GetMedium(mediumStr: ARRAY OF CHAR): SHORTINT;
  467. BEGIN
  468. IF mediumStr = 'all' THEN RETURN CSS2.All
  469. ELSIF mediumStr = 'aural' THEN RETURN CSS2.Aural
  470. ELSIF mediumStr = 'braille' THEN RETURN CSS2.Braille
  471. ELSIF mediumStr = 'embossed' THEN RETURN CSS2.Embossed
  472. ELSIF mediumStr = 'handheld' THEN RETURN CSS2.Handheld
  473. ELSIF mediumStr = 'print' THEN RETURN CSS2.Print
  474. ELSIF mediumStr = 'projection' THEN RETURN CSS2.Projection
  475. ELSIF mediumStr = 'screen' THEN RETURN CSS2.Screen
  476. ELSIF mediumStr = 'tty' THEN RETURN CSS2.TTY
  477. ELSIF mediumStr = 'tv' THEN RETURN CSS2.TV
  478. ELSE RETURN CSS2.All
  479. END
  480. END GetMedium;
  481. PROCEDURE GetPseudoPage(pseudoPageStr: ARRAY OF CHAR): SHORTINT;
  482. BEGIN
  483. IF pseudoPageStr = 'left' THEN RETURN CSS2.Left
  484. ELSIF pseudoPageStr = 'right' THEN RETURN CSS2.Right
  485. ELSIF pseudoPageStr = 'first' THEN RETURN CSS2.First
  486. ELSE RETURN CSS2.Undefined
  487. END
  488. END GetPseudoPage;
  489. (* PROCEDURE GetPseudoType(typeStr: ARRAY OF CHAR): SHORTINT;
  490. BEGIN
  491. IF typeStr = 'first-child' THEN RETURN CSS2.FirstChild
  492. ELSIF typeStr = 'link' THEN RETURN CSS2.Link
  493. ELSIF typeStr = 'visited' THEN RETURN CSS2.Visited
  494. ELSIF typeStr = 'hover' THEN RETURN CSS2.Hover
  495. ELSIF typeStr = 'active' THEN RETURN CSS2.Active
  496. ELSIF typeStr = 'focus' THEN RETURN CSS2.Focus
  497. ELSIF typeStr = 'first-line' THEN RETURN CSS2.FirstLine
  498. ELSIF typeStr = 'first-letter' THEN RETURN CSS2.FirstLetter
  499. ELSIF typeStr = 'before' THEN RETURN CSS2.Before
  500. ELSIF typeStr = 'after' THEN RETURN CSS2.After
  501. ELSE RETURN CSS2.Undefined
  502. END
  503. END GetPseudoType;*)
  504. PROCEDURE GetTermUnit(unitStr: ARRAY OF CHAR): SHORTINT;
  505. BEGIN
  506. IF unitStr = 'em' THEN RETURN CSS2.em
  507. ELSIF unitStr = 'ex' THEN RETURN CSS2.ex
  508. ELSIF unitStr = 'px' THEN RETURN CSS2.px
  509. ELSIF unitStr = 'in' THEN RETURN CSS2.in
  510. ELSIF unitStr = 'cm' THEN RETURN CSS2.cm
  511. ELSIF unitStr = 'mm' THEN RETURN CSS2.mm
  512. ELSIF unitStr = 'pt' THEN RETURN CSS2.pt
  513. ELSIF unitStr = 'pc' THEN RETURN CSS2.pc
  514. ELSIF unitStr = 'deg' THEN RETURN CSS2.deg
  515. ELSIF unitStr = 'grad' THEN RETURN CSS2.grad
  516. ELSIF unitStr = 'rad' THEN RETURN CSS2.rad
  517. ELSIF unitStr = 'ms' THEN RETURN CSS2.ms
  518. ELSIF unitStr = 's' THEN RETURN CSS2.s
  519. ELSIF unitStr = 'Hz' THEN RETURN CSS2.Hz
  520. ELSIF unitStr = 'kHz' THEN RETURN CSS2.kHz
  521. ELSE RETURN CSS2.Undefined
  522. END
  523. END GetTermUnit;
  524. PROCEDURE ComputeRGB(VAR s: ARRAY OF CHAR): LONGINT;
  525. VAR col: LONGINT; r, g, b, a: LONGINT;
  526. BEGIN
  527. HexStrToInt(s, col);
  528. IF (Strings.Length(s) = 6) OR (Strings.Length(s) = 8) THEN
  529. RETURN col
  530. ELSIF (Strings.Length(s) = 3) OR (Strings.Length(s) = 4) THEN
  531. a := col DIV 1000H; r := (col DIV 100H) MOD 10H; g := (col DIV 10H) MOD 10H; b := col MOD 10H;
  532. RETURN ASH(a, 28) + ASH(a, 24) + ASH(r, 20) + ASH(r, 16) + ASH(g, 12) + ASH(g, 8) + ASH(b, 4) + b
  533. ELSE
  534. RETURN 0
  535. END
  536. END ComputeRGB;
  537. PROCEDURE HexStrToInt(VAR str: ARRAY OF CHAR; VAR val: LONGINT);
  538. VAR i, d: LONGINT; ch: CHAR;
  539. BEGIN
  540. i := 0; ch := str[0];
  541. WHILE (ch # 0X) & (ch <= " ") DO
  542. INC(i); ch := str[i]
  543. END;
  544. val := 0;
  545. WHILE (("0" <= ch) & (ch <= "9")) OR (("A" <= ch) & (ch <= "F")) DO
  546. IF (("0" <= ch) & (ch <= "9")) THEN d := ORD(ch)-ORD("0")
  547. ELSE d := ORD(ch) - ORD("A") + 10
  548. END;
  549. INC(i); ch := str[i];
  550. val := ASH(val, 4)+d
  551. END
  552. END HexStrToInt;
  553. (* PROCEDURE SetKeyword();
  554. VAR s: DynamicStrings.String;
  555. BEGIN
  556. sym := Import;
  557. s := GetStr();
  558. IF s^ = 'import' THEN keyword := Import
  559. ELSIF s^ = 'page' THEN keyword := Page
  560. ELSIF s^ = 'media' THEN keyword := Media
  561. ELSIF s^ = 'font-face' THEN keyword := FontFace
  562. ELSIF s^ = 'charset' THEN keyword := CharSet
  563. ELSE keyword := Unknown
  564. END
  565. END SetKeyword; *)
  566. PROCEDURE DefaultReportError(pos, line, row: LONGINT; msg: ARRAY OF CHAR);
  567. BEGIN
  568. KernelLog.Enter; KernelLog.Char(CHR(9H)); KernelLog.Char(CHR(9H)); KernelLog.String("pos "); KernelLog.Int(pos, 6);
  569. KernelLog.String(", line "); KernelLog.Int(line, 0); KernelLog.String(", row "); KernelLog.Int(row, 0);
  570. KernelLog.String(" "); KernelLog.String(msg); KernelLog.Exit;
  571. END DefaultReportError;
  572. END CSS2Parser.