Syntax Highlighting에 대해서

해밝의 이미지

대부분의 에디터에서 제공하는 Syntax Highlighting 기능의 구현이 궁금한데 소스코드로는 볼 엄두가 나질 않네요. 계속 찾아보고는 있는데

간단하게 생각해본 바로는 Syntax Highlighting을 하기 위한 텍스트들을 가지고 있고 문서의 각 음절마다 비교하면서 색상을 입히기위한 코드(?)를 삽입하는 것이 한 방법이 되겠구나라고 생각했는데, 이러한 방법은 너무나 많은 오버헤드를 가질 것 같다는 생각이 듭니다.

1만개의 음절이 있고 1만개의 Syntax Highlighting을 위한 키워드가 있다고 할때 이 기능을 구현하려면 최대 1만 * 1만 번의 비교 연산이 이루어질 것같아서 말이죠.

물론 1만개의 키워드를 Syntax Highlighting하는 에디터는 없겠지만 말이죠.
이런 경우 어떠한 알고리즘을 생각할 수 있을까요?

charsyam의 이미지

poopu wrote:
대부분의 에디터에서 제공하는 Syntax Highlighting 기능의 구현이 궁금한데 소스코드로는 볼 엄두가 나질 않네요. 계속 찾아보고는 있는데

간단하게 생각해본 바로는 Syntax Highlighting을 하기 위한 텍스트들을 가지고 있고 문서의 각 음절마다 비교하면서 색상을 입히기위한 코드(?)를 삽입하는 것이 한 방법이 되겠구나라고 생각했는데, 이러한 방법은 너무나 많은 오버헤드를 가질 것 같다는 생각이 듭니다.

1만개의 음절이 있고 1만개의 Syntax Highlighting을 위한 키워드가 있다고 할때 이 기능을 구현하려면 최대 1만 * 1만 번의 비교 연산이 이루어질 것같아서 말이죠.

물론 1만개의 키워드를 Syntax Highlighting하는 에디터는 없겠지만 말이죠.
이런 경우 어떠한 알고리즘을 생각할 수 있을까요?

간단하게는 눈에 보이는 부분만... 처리를 하면 되겠죠 ^^

=========================
CharSyam ^^ --- 고운 하루
=========================

Necromancer의 이미지

컴파일러이론이 반드시 필요합니다.

여기와 관련된 이산수학, 유한상태기계(FSM), 오토마타

이런것들도 다 필요합니다.

입력된 문자열을 토큰 단위로 끊은 뒤 각각의 토쿤이

주어진 규칙에 따라 조합되는지를

실시간으로 분석해서 종류에 따라 색을 달리 나타내야 하니까요

Written By the Black Knight of Destruction

cedar의 이미지

poopu wrote:

Syntax Highlighting을 하기 위한 텍스트들을 가지고 있고 문서의 각 음절마다 비교하면서 색상을 입히기위한 코드(?)를 삽입하는 것이 한 방법이 되겠구나라고 생각했는데

맞습니다. 당연히 그런 방식으로 해야죠.
그리고 비교하는 방법은 보통 정규식(regular expression)을 사용합니다.
다음은 C++용 정규식 라이브러리중 가장 유명한 regex++의 간단한 syntax highlighting 예제입니다. 비교적 복잡한 언어인 C++코드를 문법 강조된 HTML로 변환하는 데, 실제로 돌려보면 상당히 빠릅니다.
이 코드를 기초로 하여 원하는 기능을 구현해보세요.
  /*
   *   LOCATION:    see http://www.boost.org for most recent version.
   *   FILE:        regex_merge_example.cpp
   *   VERSION:     see <boost/version.hpp>
   *   DESCRIPTION: regex_merge example:
   *                converts a C++ file to syntax highlighted HTML.
   */
 
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <iterator>
#include <boost/regex.hpp>
 
// purpose:
// takes the contents of a file and transform to
// syntax highlighted code in html format
 
const char
*pre_expression = "(<)|(>)|\\r",
*pre_format = "(?1<)(?2>)",
 
*expression_text =
  // index 1: preprocessor directives
  "(^[[:blank:]]*#(?:[^\\\\\\n]|\\\\[^\\n[:punct:][:word:]]*[\\n[:punct:][:word:]])*)|"
  // index 2: comment
  "(//[^\\n]*|/\\*.*?\\*/)|"
  // index 3: number literals
  "\\<([+-]?(?:(?:0x[[:xdigit:]]+)|(?:(?:[[:digit:]]*\\.)?[[:digit:]]+(?:[eE][+-]?[[:digit:]]+)?))u?(?:(?:int(?:8|16|32|64))|L)?)\\>|"
  // index 4: string literals
  "('(?:[^\\\\']|\\\\.)*'|\"(?:[^\\\\\"]|\\\\.)*\")|"
  // index 5: keywords
  "\\<(__asm|__cdecl|__declspec|__export|__far16|__fastcall|__fortran|__import"
  "|__pascal|__rtti|__stdcall|_asm|_cdecl|__except|_export|_far16|_fastcall"
  "|__finally|_fortran|_import|_pascal|_stdcall|__thread|__try|asm|auto|bool"
  "|break|case|catch|cdecl|char|class|const|const_cast|continue|default|delete"
  "|do|double|dynamic_cast|else|enum|explicit|extern|false|float|for|friend|goto"
  "|if|inline|int|long|mutable|namespace|new|operator|pascal|private|protected"
  "|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_cast"
  "|struct|switch|template|this|throw|true|try|typedef|typeid|typename|union|unsigned"
  "|using|virtual|void|volatile|wchar_t|while)\\>|"
  // index 6: symbol
  "([[:punct:]]|<|>)",
 
*format_string =
  "(?1<font color=\"#008040\">$&</font>)"
  "(?2<I><font color=\"#000080\">$&</font></I>)"
  "(?3<font color=\"#00A0A0\">$&</font>)"
  "(?4<font color=\"#0000FF\">$&</font>)"
  "(?5<B>$&</B>)"
  "(?6<font color=\"#800080\">$&</font>)",
 
*header_text1 = "<HTML>\n<HEAD>\n<TITLE>",
*header_text2 = "</TITLE>\n"
  "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=euc-kr\">\n"
  "</HEAD>\n<BODY LINK=\"#0000ff\" VLINK=\"#800080\" BGCOLOR=\"#ffffff\">\n"
  "<P> </P>\n<PRE>",
*footer_text = "</PRE>\n</BODY>\n</HTML>";
 
using namespace std;
 
int main(int argc, const char** argv)
{
   try{
       boost::regex e1(expression_text), e2(pre_expression);
       for(int i = 1; i < argc; ++i)
       {
          cout << "Processing file " << argv[i] << endl;
          ifstream fin(argv[i]);
          string in((istreambuf_iterator<char>(fin)),
                     istreambuf_iterator<char>());
          string out_name(argv[i]);
          out_name.append(".htm");
          ofstream fout(out_name.c_str());
          fout << header_text1 << argv[i] << header_text2;
          // strip '<' and '>' first by outputting to a
          // temporary string stream
          ostringstream t(ios::out | ios::binary);
          ostream_iterator<char> oi(t);
          boost::regex_merge(oi, in.begin(), in.end(), e2, pre_format);
          // then output to final output stream
          // adding syntax highlighting:
          string s(t.str());
          ostream_iterator<char> out(fout);
          boost::regex_merge(out, s.begin(), s.end(), e1, format_string);
          fout << footer_text;
          fout.close();
          system(out_name.c_str());
       }
   }
   catch(...)
   { return -1; }
   return 0;
}

다음은 위의 코드를 실제로 HTML로 변환한 문서의 링크입니다.
http://www.borlandforum.com/impboard/impboard.dll?action=read&db=cpp_tip&no=36
mach의 이미지

cedar wrote:

그리고 비교하는 방법은 보통 정규식(regular expression)을 사용합니다.

한표~
신택스 하이라이트시 한가지 언어에 대한 경우라면 컴파일러 구성하는 스타일로 하는 방법도 있을 수 있겠지만(실시간 신택스 검증기능 추가등을 위해...), 이러한 기능이 불필요하고 다수개 언어(스크립트)의 신택스를 하이라이트 하실 경우에는 정규식을 이용한 방법도 좋은 방법으로 생각합니다.

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

mon12key의 이미지

정규 표현식을 파서로 만들기 위해서

책을 한권 추천할께요. 한글이고 좋은 예제들이 많아요

"컴파일러 입문 , 오세만 저" 입니다.

ssehoony의 이미지

1개의 단어대해 1만개 신택스 코드 검사라...
그렇죠 평균을 따지만 5000번 비교 연산이 필요하겠죠?
그런 많은 걸 전체를 다 검색하는 건 좋은 방법이 아니고요.

소팅을 해서 divide and conquer 하는 방법도 있겠죠.
(그거 있자나요 친구가 마음 속으로 임의의 숫자를 생각하고
내가 임의의 숫자를 말하면 내가 말한것 보다 크다, 작다 를 가르쳐 주면
점점 범위를 좁혀 나가는 방법이요)

아니면 해싱을 이용하는 방법도 있겠고

트리를 구성하고 그 트리를 따라 검색하는 방법도 있겠죠.
(트리의 경우 대표적인 예로 DB의 인덱싱이 있겠네요.)

가장 빠른건 해싱일 것 같네요.
STL의 해싱을 이용하면 해싱 구현도 그리 힘들지 않을 듯 하고요.

전체를 검색하는 방법 말고는 생각을 하지 못하셨다면
[자료구조론]을 공부해 보시면 도움이 많이 되실것 같네요.

전웅의 이미지

mon12key wrote:
정규 표현식을 파서로 만들기 위해서

책을 한권 추천할께요. 한글이고 좋은 예제들이 많아요

"컴파일러 입문 , 오세만 저" 입니다.

"정규 표현식" 은 문맥에 따라 다른 (최소한 2개 이상의) 개념을 지칭하는
데 사용됩니다. 언급하신 책에서의 정규 표현식은 컴파일러 제작 (parser
부분) 을 위해 FSM 과 변환 가능한 것을 의미하며, 위의 소스를 보시면 다
른 개념의 "정규 표현식" 으로 highlighting 기능을 구현한 것을 확인하실
수 있습니다.

--
Jun, Woong (woong at gmail.com)
http://www.woong.org

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.