• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-341  評論-2670  文章-0  trackbacks-0

                詞法分析器生成器終于做好了,因此我又畫了一個狀態機然后生成了一個詞法分析器,因此開始研究IDE的智能提示的技術了。智能提示的技術有幾個要點,第一個是無論怎么慢都不能妨礙你打字,第二個是崩潰了也不能讓IDE關掉,要重啟分析器。因此我做了一個小實驗。首先我將NativeX語言的著色器跟詞法分析器都做好了,因此我要做的事情就是在你打字的時候,用另外一個線程進行詞法分析,得到結果之后用一個框框來展示出光標所在的那個token:




                注意光標所在的位置是在方框的內部。為了實現這個過程,首先我們要一個安全的多線程機制。我們把詞法分析作為一個請求來看,在打字的過程中我們就不斷把請求發送到詞法分析器頭上,然后詞法分析器分析完了就會發個消息給窗口然后傳送結果。我們注意到如果打字太快導致來不及處理的話,可能會積累若干個請求,不過那些請求實際上只有最后一個需要被處理,之前的那些來不及處理的舊請求都會被忽略。反正我們的字已經打完了,詞法分析器就不需要分析那些我們還沒打完的字了。因此我們把它抽象一下:

                我們有一個請求的類,這個類需要的數據有輸入類型、輸出類型、計算方法以及傳送方法。為什么要傳送方法呢?因為計算是在另外一個線程完成的,因此在調用傳送方法的時候也是在另外一個線程完成的,所以我們得提供一個函數來接受分析后的結果,然后用一種安全的方法傳送到我們想要的地方去。因此我們就把這個過程分成了兩個類,一個處理多線程的問題的抽象類,和一個用來提供計算方法和傳送方法的子類:
             1 using System;
             2 using System.Collections.Generic;
             3 using System.Linq;
             4 using System.Text;
             5 using System.Threading;
             6 
             7 namespace CodeBoxControl
             8 {
             9     public abstract class CalculationNotifier<I, O> : IDisposable
            10     {
            11         private Thread workingThread = null;
            12         private I analyzingInput = default(I);
            13         private bool analyzingInputAvailable = false;
            14         private Semaphore codeSemaphore = null;
            15         private object locker = null;
            16 
            17         public CalculationNotifier()
            18         {
            19             this.locker = new object();
            20             this.codeSemaphore = new Semaphore(01);
            21             this.workingThread = new Thread(Run);
            22             this.workingThread.Start();
            23         }
            24 
            25         public void Analyze(I input)
            26         {
            27             bool needRelease = false;
            28             lock (this.locker)
            29             {
            30                 if (!this.analyzingInputAvailable)
            31                 {
            32                     needRelease = true;
            33                 }
            34                 this.analyzingInputAvailable = true;
            35                 this.analyzingInput = input;
            36             }
            37             if (needRelease)
            38             {
            39                 this.codeSemaphore.Release(1);
            40             }
            41         }
            42 
            43         public void Dispose()
            44         {
            45             this.workingThread.Abort();
            46             this.codeSemaphore.Dispose();
            47         }
            48 
            49         protected abstract O Calculate(I input);
            50         protected abstract void Receive(O output);
            51 
            52         private void Run()
            53         {
            54             while (true)
            55             {
            56                 this.codeSemaphore.WaitOne();
            57                 I input = default(I);
            58                 lock (this.locker)
            59                 {
            60                     input = this.analyzingInput;
            61                     this.analyzingInputAvailable = false;
            62                 }
            63                 O output = Calculate(input);
            64                 Receive(output);
            65             }
            66         }
            67     }
            68 }
            69 

                怎么使用它呢?我們只需要不斷地把數據發送給Analyze函數,那個函數就會自動替我們處理好跟同步相關的所有問題了,然后在另外一個線程調用分析函數和返回結果:
             1 using System;
             2 using System.Collections.Generic;
             3 using System.Linq;
             4 using System.Text;
             5 using CodeBoxControl;
             6 using CodeBoxControl.CodeProvider;
             7 
             8 namespace CodeForm
             9 {
            10     class NativeXAnalyzingResult
            11     {
            12         public List<CodeToken> Tokens { getset; }
            13     }
            14 
            15     interface INativeXAnalyzingResultReceiver
            16     {
            17         void Receive(NativeXAnalyzingResult result);
            18     }
            19 
            20     class NativeXCodeAnalyzer : CalculationNotifier<string, NativeXAnalyzingResult>
            21     {
            22         private NativeXTokenizer tokenizer = new NativeXTokenizer();
            23         private INativeXAnalyzingResultReceiver receiver = null;
            24 
            25         public NativeXCodeAnalyzer(INativeXAnalyzingResultReceiver receiver)
            26         {
            27             this.receiver = receiver;
            28         }
            29 
            30         protected override NativeXAnalyzingResult Calculate(string input)
            31         {
            32             NativeXAnalyzingResult result = new NativeXAnalyzingResult();
            33             result.Tokens = this.tokenizer.Tokenize(input.ToCharArray());
            34             return result;
            35         }
            36 
            37         protected override void Receive(NativeXAnalyzingResult output)
            38         {
            39             this.receiver.Receive(output);
            40         }
            41     }
            42 }
            43 

                這個類就是用來負責做詞法分析的了。當然我們注意到此時接受數據的過程還是被抽象掉了,因為這個過程實際上應該讓插件去處理,因為插件才知道要怎么畫框。目前的控件支持兩個插件,一個是著色器,另一個是監視器。監視器負責監聽字符串的改變和插手繪圖的過程,我們可以看出這個插件是如何把詞法分析結果和畫框框聯系在一起的:
              1 using System;
              2 using System.Collections.Generic;
              3 using System.Linq;
              4 using System.Text;
              5 using CodeBoxControl;
              6 using System.Windows.Forms;
              7 using CodeBoxControl.Core;
              8 using CodeBoxControl.CodeProvider;
              9 using System.Drawing;
             10 
             11 namespace CodeForm
             12 {
             13     class NativeXControlPanel
             14         : ITextEditorControlPanel
             15         , INativeXAnalyzingResultReceiver
             16         , IDisposable
             17     {
             18         private ITextEditorControlPanelCallBack callback = null;
             19         private NativeXAnalyzingResult analyzingResult = null;
             20         private NativeXCodeAnalyzer analyzer = null;
             21 
             22         private TextPosition grayStart = new TextPosition(00);
             23         private TextPosition grayEnd = new TextPosition(00);
             24 
             25         public int Width
             26         {
             27             get
             28             {
             29                 return 0;
             30             }
             31         }
             32 
             33         public void InstallCallBack(ITextEditorControlPanelCallBack callback)
             34         {
             35             this.analyzer = new NativeXCodeAnalyzer(this);
             36             this.callback = callback;
             37             this.callback.TextEditorBox.SelectionChanged += new EventHandler(TextEditorBox_SelectionChanged);
             38         }
             39 
             40         public void OnEdit(CodeBoxControl.Core.TextPosition start, CodeBoxControl.Core.TextPosition oldEnd, CodeBoxControl.Core.TextPosition newEnd)
             41         {
             42             this.analyzer.Analyze(this.callback.TextEditorBox.Text);
             43         }
             44 
             45         public bool NeedColorLineForDisplay(int lineIndex)
             46         {
             47             return this.grayStart != this.grayEnd && this.grayStart.row <= lineIndex && lineIndex <= this.grayEnd.row;
             48         }
             49 
             50         public void ColorLineForDisplay(int lineIndex, int[] colors)
             51         {
             52             TextLine<TextEditorBox.LineInfo> line = this.callback.TextEditorBox.TextProvider[lineIndex];
             53             int length = line.CharCount;
             54 
             55             int start = grayStart.row == lineIndex ? Math.Min(grayStart.col, length) : 0;
             56             int end = grayEnd.row == lineIndex ? Math.Min(grayEnd.col, length) : line.CharCount;
             57             for (int i = start; i < end; i++)
             58             {
             59                 colors[i] = NativeXColorizer.BlockPointColorId;
             60             }
             61         }
             62 
             63         public void DrawLineBackground(Graphics g, int lineIndex, Rectangle backgroundArea)
             64         {
             65         }
             66 
             67         public void DrawLineForeground(Graphics g, int lineIndex, Rectangle backgroundArea)
             68         {
             69             if (NeedColorLineForDisplay(lineIndex))
             70             {
             71                 TextLine<TextEditorBox.LineInfo> line = this.callback.TextEditorBox.TextProvider[lineIndex];
             72                 int length = line.CharCount;
             73                 int start = grayStart.row == lineIndex ? Math.Min(grayStart.col, length) : 0;
             74                 int end = grayEnd.row == lineIndex ? Math.Min(grayEnd.col, length) : line.CharCount;
             75 
             76                 int x1 = this.callback.TextEditorBox.TextPositionToViewPoint(new TextPosition(lineIndex, start)).X;
             77                 int x2 = this.callback.TextEditorBox.TextPositionToViewPoint(new TextPosition(lineIndex, end)).X;
             78                 g.DrawRectangle(Pens.Gray, x1, backgroundArea.Top, x2 - x1, backgroundArea.Height);
             79             }
             80         }
             81 
             82         public void DrawControlPanel(Graphics g, int lineIndex, Rectangle controlPanelArea)
             83         {
             84         }
             85 
             86         public void DrawControlPanelBackground(Graphics g, Rectangle backgroundArea)
             87         {
             88         }
             89 
             90         public void OnMouseDown(int lineIndex, Rectangle controlPanelArea, Point relativePosition, System.Windows.Forms.MouseButtons buttons)
             91         {
             92         }
             93 
             94         public void OnMouseMove(int lineIndex, Rectangle controlPanelArea, Point relativePosition, System.Windows.Forms.MouseButtons buttons)
             95         {
             96         }
             97 
             98         public void OnMouseUp(int lineIndex, Rectangle controlPanelArea, Point relativePosition, System.Windows.Forms.MouseButtons buttons)
             99         {
            100         }
            101 
            102         public void Receive(NativeXAnalyzingResult result)
            103         {
            104             this.callback.TextEditorBox.Invoke(new MethodInvoker(() =>
            105             {
            106                 this.analyzingResult = result;
            107                 UpdateBlock();
            108             }));
            109         }
            110 
            111         public void Dispose()
            112         {
            113             this.analyzer.Dispose();
            114         }
            115 
            116         private void UpdateBlock()
            117         {
            118             NativeXAnalyzingResult result = this.analyzingResult;
            119             TextPosition pos = this.callback.TextEditorBox.SelectionCaret;
            120             if (result != null)
            121             {
            122                 foreach (CodeToken token in result.Tokens)
            123                 {
            124                     if (token.Start < pos && pos < token.End)
            125                     {
            126                         this.grayStart = token.Start;
            127                         this.grayEnd = token.End;
            128                         return;
            129                     }
            130                 }
            131                 this.grayStart = new TextPosition(00);
            132                 this.grayEnd = new TextPosition(00);
            133             }
            134         }
            135 
            136         private void TextEditorBox_SelectionChanged(object sender, EventArgs e)
            137         {
            138             UpdateBlock();
            139         }
            140     }
            141 }
            142 


                這里我們借助了System.Windows.Forms.Control.Invoke來將一整個閉包壓到了消息循環里面,然后消息循環來執行這個閉包,因此接收數據的過程就在UI線程上完成了。Invoke跟SendMessage其實是差不多的。我們還能看出這個插件的接口叫ControlPanel,所以是用來干預一切變化的。這里有Width屬性但是設置成0了,如果不是0的話就可以模仿VisualStudio左邊那個放斷點的控制欄了,這個在之前已經演示過了。

                到這里如何在非UI線程處理代碼的技術就介紹完了,現在讓我們來看著色器和詞法分析器的樣子哈。首先上著色器的狀態機:


                然后是詞法分析器的狀態機:


                至于他們生成的代碼,可以去Vczh Library++ 3.0這里看哈。

             

            posted on 2010-10-14 08:23 陳梓瀚(vczh) 閱讀(5861) 評論(6)  編輯 收藏 引用 所屬分類: 開發自己的IDE

            評論:
            # re: 開發自己的IDE(六)[未登錄] 2010-10-14 08:33 | Lyt
            看一次流一次口水…  回復  更多評論
              
            # re: 開發自己的IDE(六) 2010-10-14 16:51 | Pear
            MB真帥氣。。MB真帥氣。。真帥氣。。  回復  更多評論
              
            # re: 開發自己的IDE(六) 2010-10-16 07:57 | mm
            好強大!!!  回復  更多評論
              
            # re: 開發自己的IDE(六) 2010-10-17 08:45 | hhh2000
            圖有點小,有些符號看不清楚……

            對著色器狀態機的圖有點疑問:1、如果CharIn是指單個字符的話,好像少了一個狀態。2、StringIn指向自己的邊是非 \ 和 " 號嗎(圖看不清)?這好像不大對吧。還

            有單雙引號一般只影響本行,加上一個行尾的狀態約束一下,這樣在引號不匹配的情況下看起來會好一些。
              回復  更多評論
              
            # re: 開發自己的IDE(六) 2010-10-19 01:41 | 陳梓瀚(vczh)
            @hhh2000
            為了簡單,char我還是允許他擁有多個字符了,反正對于一個字符的狀態可以正確解析,而且這是用在IDE上面的,勢必跟編譯器會有一些小的區別

            StringIn那個東西是\.哈,也就是任意字符的意思。  回復  更多評論
              
            # re: 開發自己的IDE(六) 2010-10-19 01:42 | 陳梓瀚(vczh)
            @hhh2000
            到了行末尾其實就是一個\n字符,只要你在狀態機上面把\n給排除了,自然就會只有一行了。  回復  更多評論
              
            一本一本久久a久久综合精品蜜桃| 欧美久久精品一级c片片| 99久久人妻无码精品系列| 亚洲狠狠婷婷综合久久久久| 久久本道久久综合伊人| 91精品国产色综久久| 久久久久久久久久免免费精品 | 91久久九九无码成人网站| 久久中文娱乐网| 久久精品无码一区二区三区| 亚洲综合精品香蕉久久网97| 久久美女人爽女人爽| 情人伊人久久综合亚洲| 久久九九免费高清视频| 日韩人妻无码一区二区三区久久99| 亚洲中文精品久久久久久不卡| 精品免费久久久久久久| 久久ZYZ资源站无码中文动漫| 国产成人AV综合久久| 人人狠狠综合久久亚洲| 无码任你躁久久久久久老妇App| 国产精品免费福利久久| 99精品久久久久久久婷婷| 亚洲国产成人久久精品99| 99精品国产在热久久无毒不卡 | 91性高湖久久久久| 久久亚洲国产精品五月天婷| 国内精品久久久久影院日本 | 老司机午夜网站国内精品久久久久久久久| 欧美激情精品久久久久久久九九九| 国内精品综合久久久40p| 久久精品人人做人人爽电影蜜月 | 人人妻久久人人澡人人爽人人精品 | 久久久久亚洲AV无码专区体验| 久久99久久无码毛片一区二区 | 久久不见久久见免费影院www日本| 久久强奷乱码老熟女网站 | 久久国产香蕉视频| 久久亚洲日韩精品一区二区三区| 亚洲精品tv久久久久久久久久| 久久国产一区二区|