Subversion Repositories Kolibri OS

Rev

Rev 9902 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. (*
  2.     Copyright 2021-2023 Anton Krotov
  3.  
  4.     This file is part of CEdit.
  5.  
  6.     CEdit is free software: you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation, either version 3 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     CEdit is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with CEdit. If not, see <http://www.gnu.org/licenses/>.
  18. *)
  19.  
  20. MODULE Languages;
  21.  
  22. IMPORT Lines, Utils;
  23.  
  24.  
  25. CONST
  26.  
  27.     langText* = 0; langC* = 1; langOberon* = 2; langPascal* = 3;
  28.     langFasm* = 4; langLua* = 5; langIni* = 6; langJSON* = 7;
  29.  
  30.     csLang = {langC, langOberon, langLua, langIni, langJSON};
  31.     escLang* = {langC, langLua, langJSON};
  32.  
  33. TYPE
  34.  
  35.     tLine = Lines.tLine;
  36.  
  37.     tKeyWords = RECORD
  38.         words: ARRAY 200, 32 OF WCHAR; cnt: INTEGER
  39.     END;
  40.  
  41.     tDelimiters = ARRAY 256 OF BOOLEAN;
  42.  
  43.     procGetStr = PROCEDURE (secName, keyName: ARRAY OF CHAR; VAR s: ARRAY OF CHAR);
  44.  
  45.  
  46. VAR
  47.  
  48.         KW: ARRAY 8 OF ARRAY 3 OF tKeyWords;
  49.         Delim: ARRAY 8 OF tDelimiters;
  50.  
  51.     currentLang: INTEGER;
  52.  
  53.     fileExt: ARRAY 11 OF RECORD ext: ARRAY 8 OF CHAR; lang: INTEGER END;
  54.  
  55.  
  56. PROCEDURE isCS* (lang: INTEGER): BOOLEAN;
  57.     RETURN lang IN csLang
  58. END isCS;
  59.  
  60.  
  61. PROCEDURE checkKW (s: ARRAY OF WCHAR; KW: tKeyWords): BOOLEAN;
  62. VAR
  63.     i: INTEGER;
  64. BEGIN
  65.     i := KW.cnt - 1;
  66.     WHILE (i >= 0) & (s # KW.words[i]) DO
  67.         DEC(i)
  68.     END
  69.     RETURN i >= 0
  70. END checkKW;
  71.  
  72.  
  73. PROCEDURE isKey* (s: ARRAY OF WCHAR; lang, kwSet: INTEGER): BOOLEAN;
  74.     RETURN checkKW(s, KW[lang][kwSet - 1])
  75. END isKey;
  76.  
  77.  
  78. PROCEDURE isDelim* (c: WCHAR): BOOLEAN;
  79. VAR
  80.         res: BOOLEAN;
  81. BEGIN
  82.         IF c <= 0FFX THEN
  83.                 res := Delim[currentLang][ORD(c)]
  84.         ELSE
  85.                 res := FALSE
  86.         END
  87.         RETURN res
  88. END isDelim;
  89.  
  90.  
  91. PROCEDURE SkipString* (line: tLine; VAR pos: INTEGER; n: INTEGER; lang: INTEGER);
  92. VAR
  93.     quot, cur, prev: WCHAR;
  94. BEGIN
  95.     quot := Lines.getChar(line, pos);
  96.     cur := quot;
  97.     prev := 0X;
  98.     INC(pos);
  99.     WHILE pos <= n DO
  100.         IF lang IN escLang THEN
  101.                 prev := cur
  102.         END;
  103.         cur := Lines.getChar(line, pos);
  104.         IF (cur = "\") & (prev = "\") THEN
  105.                 cur := 0X
  106.         ELSIF (cur = quot) & (prev # "\") THEN
  107.                 n := 0; (* exit *)
  108.                 DEC(pos)
  109.         END;
  110.         INC(pos)
  111.     END
  112. END SkipString;
  113.  
  114.  
  115. PROCEDURE SkipEsc* (line: tLine; VAR pos: INTEGER; n: INTEGER; lang: INTEGER);
  116. VAR
  117.         c, c1: WCHAR;
  118.         k: INTEGER;
  119. BEGIN
  120.         IF pos < n THEN
  121.                 c := Lines.getChar(line, pos + 1);
  122.                 CASE lang OF
  123.                 |langC:
  124.                         IF Utils.inString(c, "abfnrtv\'?" + '"') THEN
  125.                                 INC(pos)
  126.                         ELSIF Utils.isOct(c) THEN
  127.                                 k := 0;
  128.                                 REPEAT
  129.                                         INC(pos);
  130.                                         IF Utils.isOct(Lines.getChar(line, pos)) THEN
  131.                                                 INC(k)
  132.                                         ELSE
  133.                                                 k := 0
  134.                                         END
  135.                                 UNTIL (k = 0) OR (k = 4);
  136.                                 DEC(pos)
  137.                         ELSIF (c = "x") OR (c = "u") OR (c = "U") THEN
  138.                                 c1 := c;
  139.                                 k := 0;
  140.                                 INC(pos);
  141.                                 REPEAT
  142.                                         INC(pos);
  143.                                         c := Lines.getChar(line, pos);
  144.                                         IF Utils.upper(c) THEN END;
  145.                                         IF Utils.isHex(c) THEN
  146.                                                 INC(k)
  147.                                         ELSE
  148.                                                 k := 0
  149.                                         END;
  150.                                         IF (c1 = "u") & (k = 5) OR (c1 = "U") & (k = 9) THEN
  151.                                                 k := 0
  152.                                         END
  153.                                 UNTIL k = 0;
  154.                                 DEC(pos)
  155.                         END
  156.                 |langLua:
  157.                         IF Utils.inString(c, "abfnrtv\'[]" + '"') THEN
  158.                                 INC(pos)
  159.                         END
  160.                 |langJSON:
  161.                         IF Utils.inString(c, 'bfnrt\/"') THEN
  162.                                 INC(pos)
  163.                         ELSIF c = "u" THEN
  164.                                 k := 0;
  165.                                 INC(pos);
  166.                                 REPEAT
  167.                                         INC(pos);
  168.                                         c := Lines.getChar(line, pos);
  169.                                         IF Utils.upper(c) THEN END;
  170.                                         IF Utils.isHex(c) THEN
  171.                                                 INC(k)
  172.                                         ELSE
  173.                                                 k := 0
  174.                                         END
  175.                                 UNTIL (k = 0) OR (k = 5);
  176.                                 DEC(pos)
  177.                         END
  178.                 END
  179.         END
  180. END SkipEsc;
  181.  
  182.  
  183. PROCEDURE C (line: tLine; VAR depth, cond, pos: INTEGER; n: INTEGER);
  184. VAR
  185.     c: WCHAR;
  186. BEGIN
  187.     c := Lines.getChar(line, pos);
  188.     IF depth = 0 THEN
  189.         IF c = "/" THEN
  190.             IF cond = 0 THEN
  191.                 cond := 1
  192.             ELSE
  193.                 cond := 0;
  194.                 pos := n
  195.             END
  196.         ELSIF (c = "*") & (cond = 1) THEN
  197.             depth := 1;
  198.             cond := 0
  199.         ELSIF (c = "'") OR (c = '"') THEN
  200.             SkipString(line, pos, n, langC);
  201.             cond := 0
  202.         ELSE
  203.             cond := 0
  204.         END
  205.     ELSIF depth = 1 THEN
  206.         IF c = "*" THEN
  207.             cond := 1
  208.         ELSIF (c = "/") & (cond = 1) THEN
  209.             cond := 0;
  210.             depth := 0
  211.         ELSE
  212.             cond := 0
  213.         END
  214.     END
  215. END C;
  216.  
  217.  
  218. PROCEDURE LuaLong* (line: tLine; pos: INTEGER): INTEGER;
  219. VAR
  220.     res: INTEGER;
  221. BEGIN
  222.     res := -1;
  223.     IF Lines.getChar(line, pos) = "[" THEN
  224.         INC(pos);
  225.         WHILE Lines.getChar(line, pos) = "=" DO
  226.             INC(res);
  227.             INC(pos)
  228.         END;
  229.         IF Lines.getChar(line, pos) = "[" THEN
  230.             INC(res)
  231.         ELSE
  232.             res := -1
  233.         END
  234.     END
  235.     RETURN res
  236. END LuaLong;
  237.  
  238.  
  239. PROCEDURE Lua (line: tLine; VAR depth, cond, pos: INTEGER; n: INTEGER);
  240. VAR
  241.     c: WCHAR;
  242.     k: INTEGER;
  243. BEGIN
  244.     c := Lines.getChar(line, pos);
  245.     IF depth = 0 THEN
  246.         IF c = "-" THEN
  247.             IF cond = 0 THEN
  248.                 cond := 1
  249.             ELSE
  250.                 cond := 0;
  251.                 k := LuaLong(line, pos + 1);
  252.                 IF k >= 0 THEN
  253.                     depth := k*2 + 1
  254.                 ELSE
  255.                     pos := n
  256.                 END
  257.             END
  258.         ELSIF c = "[" THEN
  259.             cond := 0;
  260.             k := LuaLong(line, pos);
  261.             IF k >= 0 THEN
  262.                 depth := (k + 1)*2
  263.             END
  264.         ELSIF (c = "'") OR (c = '"') THEN
  265.             SkipString(line, pos, n, langLua);
  266.             cond := 0
  267.         ELSE
  268.             cond := 0
  269.         END
  270.     ELSIF depth > 0 THEN
  271.         IF (cond = 0) & (c = "]") THEN
  272.             cond := 1
  273.         ELSIF (cond >= 1) & (c = "=") THEN
  274.             INC(cond)
  275.         ELSIF (cond >= 1) & (c = "]") & (cond*2 - depth MOD 2 = depth) THEN
  276.             depth := 0;
  277.             cond := 0
  278.         ELSE
  279.             cond := 0
  280.         END
  281.     END
  282. END Lua;
  283.  
  284.  
  285. PROCEDURE Pascal (line: tLine; VAR depth, cond, pos: INTEGER; n: INTEGER);
  286. VAR
  287.     c: WCHAR;
  288. BEGIN
  289.     c := Lines.getChar(line, pos);
  290.     IF depth = 0 THEN
  291.         IF c = "(" THEN
  292.             cond := 1
  293.         ELSIF c = "/" THEN
  294.             IF cond = 2 THEN
  295.                 cond := 0;
  296.                 pos := n
  297.             ELSE
  298.                 cond := 2
  299.             END
  300.         ELSIF (c = "*") & (cond = 1) THEN
  301.             depth := 2;
  302.             cond := 0
  303.         ELSIF c = "'" THEN
  304.             SkipString(line, pos, n, langPascal);
  305.             cond := 0
  306.         ELSIF c = "{" THEN
  307.             IF Lines.getChar(line, pos + 1) = "$" THEN
  308.                 depth := 3
  309.             ELSE
  310.                 depth := 1
  311.             END;
  312.             cond := 0
  313.         ELSE
  314.             cond := 0
  315.         END
  316.     ELSIF depth IN {1, 3} THEN
  317.         IF c = "}" THEN
  318.             depth := 0
  319.         END
  320.     ELSIF depth = 2 THEN
  321.         IF c = "*" THEN
  322.             cond := 1
  323.         ELSIF (c = ")") & (cond = 1) THEN
  324.             depth := 0;
  325.             cond := 0
  326.         ELSE
  327.             cond := 0
  328.         END
  329.     END
  330. END Pascal;
  331.  
  332.  
  333. PROCEDURE Oberon (line: tLine; VAR depth, cond, pos: INTEGER; n: INTEGER);
  334. VAR
  335.     c: WCHAR;
  336. BEGIN
  337.     c := Lines.getChar(line, pos);
  338.     IF (depth = 0) & (c = "/") THEN
  339.         IF cond = 3 THEN
  340.             cond := 0;
  341.             pos := n
  342.         ELSE
  343.             cond := 3
  344.         END
  345.     ELSIF (depth = 0) & ((c = "'") OR (c = '"')) THEN
  346.         SkipString(line, pos, n, langOberon);
  347.         cond := 0
  348.     ELSIF c = "(" THEN
  349.         cond := 1
  350.     ELSIF c = "*" THEN
  351.         IF cond = 1 THEN
  352.             INC(depth);
  353.             cond := 0
  354.         ELSE
  355.             cond := 2
  356.         END
  357.     ELSIF c = ")" THEN
  358.         IF cond = 2 THEN
  359.             IF depth > 0 THEN
  360.                 DEC(depth)
  361.             END
  362.         END;
  363.         cond := 0
  364.     ELSE
  365.         cond := 0
  366.     END;
  367. END Oberon;
  368.  
  369.  
  370. PROCEDURE Ini (line: tLine; VAR depth, cond, pos: INTEGER; n: INTEGER);
  371. VAR
  372.     c: WCHAR;
  373. BEGIN
  374.     cond := 0;
  375.     c := Lines.getChar(line, pos);
  376.     IF depth = 0 THEN
  377.         IF c = ";" THEN
  378.             pos := n
  379.         ELSIF c = '"' THEN
  380.             SkipString(line, pos, n, langIni)
  381.         ELSIF c = "[" THEN
  382.             depth := 1
  383.         END
  384.     ELSIF depth = 1 THEN
  385.         IF c = "]" THEN
  386.             depth := 0
  387.         END
  388.     END
  389. END Ini;
  390.  
  391.  
  392. PROCEDURE comments* (line: tLine; VAR depth, cond, pos: INTEGER; n: INTEGER; lang: INTEGER);
  393. BEGIN
  394.     CASE lang OF
  395.     |langText:
  396.     |langFasm:
  397.     |langC,
  398.      langJSON:    C(line, depth, cond, pos, n)
  399.     |langOberon:  Oberon(line, depth, cond, pos, n)
  400.     |langPascal:  Pascal(line, depth, cond, pos, n)
  401.     |langLua:     Lua(line, depth, cond, pos, n)
  402.     |langIni:     Ini(line, depth, cond, pos, n)
  403.     END
  404. END comments;
  405.  
  406.  
  407. PROCEDURE EnterKW (s: ARRAY OF CHAR; VAR KW: tKeyWords);
  408. CONST
  409.     SPACE = 20X; CR = 0DX; LF = 0AX; TAB = 9X; COMMA = ",";
  410. VAR
  411.     i, j, k: INTEGER;
  412.  
  413.     PROCEDURE delim (c: CHAR): BOOLEAN;
  414.         RETURN (c = COMMA) OR (c = SPACE) OR (c = CR) OR (c = LF) OR (c = TAB)
  415.     END delim;
  416.  
  417. BEGIN
  418.     k := KW.cnt;
  419.     i := 0;
  420.     REPEAT
  421.         j := 0;
  422.         WHILE (s[i] # 0X) & ~delim(s[i]) DO
  423.             KW.words[k, j] := WCHR(ORD(s[i]));
  424.             INC(i);
  425.             INC(j)
  426.         END;
  427.         KW.words[k, j] := 0X;
  428.         INC(k);
  429.         WHILE delim(s[i]) DO
  430.             INC(i)
  431.         END
  432.     UNTIL s[i] = 0X;
  433.     KW.cnt := k
  434. END EnterKW;
  435.  
  436.  
  437. PROCEDURE loadKW (lang: INTEGER; VAR KW: ARRAY OF tKeyWords; VAR delim: tDelimiters; getStr: procGetStr;
  438.                                         lang_name: ARRAY OF CHAR);
  439. VAR
  440.     s: ARRAY 16*1024 OF CHAR;
  441.     key: ARRAY 4 OF CHAR;
  442.     i, j, k: INTEGER;
  443.     w: WCHAR;
  444. BEGIN
  445.         FOR i := 0 TO LEN(delim) - 1 DO
  446.                 delim[i] := FALSE
  447.         END;
  448.         getStr(lang_name, "delim", s);
  449.         i := 0;
  450.         WHILE s[i] # 0X DO
  451.                 delim[ORD(s[i])] := TRUE;
  452.                 INC(i)
  453.         END;
  454.     key := "KW1";
  455.     FOR i := 0 TO 2 DO
  456.         KW[i].cnt := 0;
  457.         key[2] := CHR(ORD("1") + i);
  458.         getStr(lang_name, key, s);
  459.         IF ~(lang IN csLang) THEN
  460.                 Utils.lowcase8(s)
  461.         END;
  462.         IF lang = langOberon THEN
  463.                 k := LENGTH(s);
  464.             s[k] := ",";
  465.                 FOR j := 0 TO k - 1 DO
  466.                         s[j + k + 1] := s[j];
  467.                         w := WCHR(ORD(s[j]));
  468.                         IF Utils.lower(w) THEN
  469.                                 s[j + k + 1] := CHR(ORD(w) MOD 256)
  470.                         END
  471.             END;
  472.             k := 2*k + 1;
  473.             s[k] := 0X
  474.         END;
  475.         EnterKW(s, KW[i])
  476.     END
  477. END loadKW;
  478.  
  479.  
  480. PROCEDURE setCurLang* (lang: INTEGER);
  481. BEGIN
  482.         currentLang := lang
  483. END setCurLang;
  484.  
  485.  
  486. PROCEDURE getLang* (ext: ARRAY OF CHAR): INTEGER;
  487. VAR
  488.         i: INTEGER;
  489. BEGIN
  490.         i := 0;
  491.         WHILE (i < LEN(fileExt)) & (fileExt[i].ext # ext) DO
  492.                 INC(i)
  493.         END;
  494.         IF i < LEN(fileExt) THEN
  495.                 i := fileExt[i].lang
  496.         ELSE
  497.                 i := langText
  498.         END
  499.         RETURN i
  500. END getLang;
  501.  
  502.  
  503. PROCEDURE getExt* (lang: INTEGER; VAR ext: ARRAY OF CHAR);
  504. VAR
  505.         i: INTEGER;
  506. BEGIN
  507.         i := 0;
  508.         WHILE fileExt[i].lang # lang DO
  509.                 INC(i)
  510.         END;
  511.         COPY(fileExt[i].ext, ext)
  512. END getExt;
  513.  
  514.  
  515. PROCEDURE init* (getStr: procGetStr);
  516. BEGIN
  517.         currentLang := langText;
  518.         loadKW(langText,   KW[langText],   Delim[langText],   getStr, "lang_Text");
  519.     loadKW(langOberon, KW[langOberon], Delim[langOberon], getStr, "lang_Oberon");
  520.     loadKW(langC,      KW[langC],      Delim[langC],      getStr, "lang_C");
  521.     loadKW(langPascal, KW[langPascal], Delim[langPascal], getStr, "lang_Pascal");
  522.     loadKW(langLua,    KW[langLua],    Delim[langLua],    getStr, "lang_Lua");
  523.     loadKW(langIni,    KW[langIni],    Delim[langIni],    getStr, "lang_Ini");
  524.     loadKW(langFasm,   KW[langFasm],   Delim[langFasm],   getStr, "lang_Fasm");
  525.     loadKW(langJSON,   KW[langJSON],   Delim[langJSON],   getStr, "lang_JSON");
  526.  
  527.     fileExt[ 0].ext := "ob07"; fileExt[ 0].lang := langOberon;
  528.     fileExt[ 1].ext := "c";    fileExt[ 1].lang := langC;
  529.     fileExt[ 2].ext := "h";    fileExt[ 2].lang := langC;
  530.     fileExt[ 3].ext := "cpp";  fileExt[ 3].lang := langC;
  531.     fileExt[ 4].ext := "pas";  fileExt[ 4].lang := langPascal;
  532.     fileExt[ 5].ext := "pp";   fileExt[ 5].lang := langPascal;
  533.     fileExt[ 6].ext := "asm";  fileExt[ 6].lang := langFasm;
  534.     fileExt[ 7].ext := "lua";  fileExt[ 7].lang := langLua;
  535.     fileExt[ 8].ext := "ini";  fileExt[ 8].lang := langIni;
  536.     fileExt[ 9].ext := "json"; fileExt[ 9].lang := langJSON;
  537.     fileExt[10].ext := "txt";  fileExt[10].lang := langText;
  538. END init;
  539.  
  540.  
  541. END Languages.