Subversion Repositories Kolibri OS

Rev

Rev 9659 | Rev 9892 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. (*
  2.     Copyright 2021, 2022 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.cap(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.cap(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 (VAR KW: ARRAY OF tKeyWords; VAR delim: tDelimiters; getStr: procGetStr; lang: ARRAY OF CHAR);
  438. VAR
  439.     s: ARRAY 16*1024 OF CHAR;
  440.     key: ARRAY 4 OF CHAR;
  441.     i: INTEGER;
  442. BEGIN
  443.         FOR i := 0 TO LEN(delim) - 1 DO
  444.                 delim[i] := FALSE
  445.         END;
  446.         getStr(lang, "delim", s);
  447.         i := 0;
  448.         WHILE s[i] # 0X DO
  449.                 delim[ORD(s[i])] := TRUE;
  450.                 INC(i)
  451.         END;
  452.     key := "KW1";
  453.     FOR i := 0 TO 2 DO
  454.         KW[i].cnt := 0;
  455.         key[2] := CHR(ORD("1") + i);
  456.         getStr(lang, key, s);
  457.         EnterKW(s, KW[i])
  458.     END
  459. END loadKW;
  460.  
  461.  
  462. PROCEDURE setCurLang* (lang: INTEGER);
  463. BEGIN
  464.         currentLang := lang
  465. END setCurLang;
  466.  
  467.  
  468. PROCEDURE getLang* (ext: ARRAY OF CHAR): INTEGER;
  469. VAR
  470.         i: INTEGER;
  471. BEGIN
  472.         i := 0;
  473.         WHILE (i < LEN(fileExt)) & (fileExt[i].ext # ext) DO
  474.                 INC(i)
  475.         END;
  476.         IF i < LEN(fileExt) THEN
  477.                 i := fileExt[i].lang
  478.         ELSE
  479.                 i := langText
  480.         END
  481.         RETURN i
  482. END getLang;
  483.  
  484.  
  485. PROCEDURE getExt* (lang: INTEGER; VAR ext: ARRAY OF CHAR);
  486. VAR
  487.         i: INTEGER;
  488. BEGIN
  489.         i := 0;
  490.         WHILE fileExt[i].lang # lang DO
  491.                 INC(i)
  492.         END;
  493.         COPY(fileExt[i].ext, ext);
  494.         Utils.lowcase(ext)
  495. END getExt;
  496.  
  497.  
  498. PROCEDURE init* (getStr: procGetStr);
  499. BEGIN
  500.         currentLang := langText;
  501.         loadKW(KW[langText],   Delim[langText],   getStr, "lang_Text");
  502.     loadKW(KW[langOberon], Delim[langOberon], getStr, "lang_Oberon");
  503.     loadKW(KW[langC],      Delim[langC],      getStr, "lang_C");
  504.     loadKW(KW[langPascal], Delim[langPascal], getStr, "lang_Pascal");
  505.     loadKW(KW[langLua],    Delim[langLua],    getStr, "lang_Lua");
  506.     loadKW(KW[langIni],    Delim[langIni],    getStr, "lang_Ini");
  507.     loadKW(KW[langFasm],   Delim[langFasm],   getStr, "lang_Fasm");
  508.     loadKW(KW[langJSON],   Delim[langJSON],   getStr, "lang_JSON");
  509.  
  510.     fileExt[ 0].ext := "OB07"; fileExt[ 0].lang := langOberon;
  511.     fileExt[ 1].ext := "C";    fileExt[ 1].lang := langC;
  512.     fileExt[ 2].ext := "H";    fileExt[ 2].lang := langC;
  513.     fileExt[ 3].ext := "CPP";  fileExt[ 3].lang := langC;
  514.     fileExt[ 4].ext := "PAS";  fileExt[ 4].lang := langPascal;
  515.     fileExt[ 5].ext := "PP";   fileExt[ 5].lang := langPascal;
  516.     fileExt[ 6].ext := "ASM";  fileExt[ 6].lang := langFasm;
  517.     fileExt[ 7].ext := "LUA";  fileExt[ 7].lang := langLua;
  518.     fileExt[ 8].ext := "INI";  fileExt[ 8].lang := langIni;
  519.     fileExt[ 9].ext := "JSON"; fileExt[ 9].lang := langJSON;
  520.     fileExt[10].ext := "TXT";  fileExt[10].lang := langText;
  521. END init;
  522.  
  523.  
  524. END Languages.