pretty code

2024年1月17日 星期三

神奇的正規表示法

每次都覺得正規表示法很神奇,換了一個工具就有該工具的眉角要注意!

最近沒有意外應該都會在 Linux 下工作,sed 是一個很常用的工具,常用來取代檔案的字串用。

sed 和 grep 一樣,有分 BRE 和 ERE 兩種模式,-E 則代表使用 ERE。

昨天看到一篇文章,剛好有個範例可以練習,沒想到一直試不成功。

下午在寫完簡報後,突然福至心靈的解決了,順便記錄一下。

有一個檔案內容如下:

<html><head><title>Hello World</title>
<body>Welcome to the world of regexp!</body></html>

想要使用 sed 取出非 HTML tag 的內容。

原本是使用 BRE 無法成功
sed -n 's/<.*>\([a-zA-Z !]+\)<\/.*>/\1/p' fileName

改使用 ERE 即可
sed -En 's/<.*>([a-zA-Z !]+)<\/.*>/\1/p' fileName

Note: 上面的 Rex 似乎要把整行都明確表示出來,否則達不到我們要的效果

2024年1月13日 星期六

星星之火,可以燎原

程式 Bug 就是如此神奇?

快兩個月前發現 Daily Money 因為資料庫筆數已經突破 20,179 筆,導致明細報表無法在既定的時間內完成而產生 ANR。

當時因為忙於交接,故只用最快的方式找到錯誤的地方做點小 patch,但因為沒有仔細研究,所以留下了一個小 Bug,在切換月份的時候日期就會整個錯亂XD

原來 currentDate 是有意義的,當按 Prev() or Next() 時,currentDate 會變動,currentEndDate 也會隨之變動,故我不能重新計算 currentDate 的值!

當初只改 4 行以為解決了 ANR 問題,沒想到也留下一個月報表及年報表的錯誤,果然星星之火可以燎原,雖然現在只要 2 行就可修復。

簡單做了點驗證,希望兩個月後不要再發生其他問題XD

目前資料筆數來到 20,450 筆。


2024/01/15 更新

稍微再多看一點 code,釐清了幾個地方。

totalMode = 1 表示是資產負債表。

currentDate 會在按下 Prev() or Next() or Today() 時改變,接著呼叫 reloadData(),在這裡會重新計算 currentStartDate 和 currentEndDate,也是在這裡面依 totalMode 決定 currentStartDate 是不是 null。

故嚴格來說,兩個月前為了解決 ANR,應該把 patch 改在這裡,比較符合原開發者的意思。

2024年1月4日 星期四

Some tips in Makefile - 003

01. $(XXX:.lib=_.lib)

WRAP_LIBS = abc.lib def.so
$(info $(WRAP_LIBS:.lib=_.lib))

將 XXX 變數裡的 ".lib" 字串變成 "_.lib"

$(patsubst %.lib,%_.lib, $(WRAP_LIBS)))

也可以用 patsubst 函數,但 %_.lib 前面不能有空格,否則被取代的字串前面會多一個空格。

2023年12月29日 星期五

Some tips in Makefile - 002

01. export 

ABC ?= abc

上面表示如果 $(ABC) 未定義,則值等於 abc。

我們可以在呼叫 make 前,在 Shell 下 export ABC=ddd,則 Makefile 中就可以看到被定義成 ddd,另外一種方式則是 make ABC=ddd xxxx_target。

如果在 Makefile 中寫成 export ABC ?= abc,則這個 $(ABC) 可以傳遞到其他的程序。

假設是這樣執行 $(shell ./test.sh),即使用了 export,test.sh 中也看不到 $ABC 這個變數,這部份待確認?

順帶一提,在 Shell 下使用 export 則是將變數傳給其他的程序,比如另一個 shell script 或是執行檔等,像 C 語言可以用 getenv 取的環境變數。

02. 只看 make 執行過程,不真正執行

make -n 即可。

03. 使用 wildcard, abspath, notdir

像是在 Makefile 印出當前目錄下的所有檔案但不包括目錄本身,如果要絕對路徑則是用 abspath 取代 notdir 即可。

$(foreach log, $(notdir  $(wildcard ./*.log), $(info $(log)))

另外,foreach 語法如下:

$(foreach n, list, text)

list 是一串用空白分隔的字串,n 是當前取到的單一字串,text 則是你要做的事。

04. $@, $^, $<, $?, $*

有一 rule 如下:

main.o:    main.c def.h
            gcc -c main.c

假設 def.h 有更動過。

$@ = main.o  --> target
$^ = main.c  def.h  --> dependence
$< = main.c  --> first dependence
$? = def.h  --> changed file
$* = main  --> the primary name of target

故 gcc -c main.c  可以寫成 gcc -c $<。

另外,假設 target = all,則 $* 是空字串,因為 all 沒有副檔名。

2023年12月28日 星期四

Some tips in Makefile - 001

今天開始接觸未來可能的工作流程,雖然只是練習用,但也算是有點感覺了。

主管還很貼心的提供了一個小測驗,由於我對 Tcl 或是 Makefile 都只是略懂,一開始先花點時間整理脈絡,直到看到主管說的關鍵字後,便開始主攻這個測驗。

雖然這個測驗有點像腦筋急轉彎?但在一步一步分解問題後,最後還是能找到解法,但我也花了一個小時多有,還好在吃飯前順利搞定。

簡單快速紀錄一下,今天學到的東西XD

01. Makefile 變數賦值

= 在使用到變數時展開。
:= 宣告變數時就展開。
?= 變數為空時才給值。
+= 將值附加到原本變數。

02. .DEFAULT_GOAL

如題,此變數為 GNU make 的一個特殊變數,有設定這個,假設 make 後面沒帶 target 就會以這個變數為主,而不是檔案中找到的第一個 target。

03. $$0 in awk command of Makefile

原本 awk 取原始字串是 $0,但在 Makefile 中 $ 有特殊用途,故在 awk 指令中,需要多加一個 $。

另外,如果想印出 $@,則應該要這樣寫 @echo \$$@。

04. env variable in Tcl

puts $::env(OS),此指令的意思是印出 OS 這個環境變數,env 本身是 array,array in Tcl 是關聯陣列。

05. call proc in some Tcl files.

source $::env(SCRIPTS_DIR)/report_metrics.tcl
report_metrics 6 "finish"

report_metrics.tcl 檔案中都是函數,這樣就可以呼叫該檔案裡面的 report_metrics 函數。

06. /usr/bin/time -f '%E %MKb' sleep 5

time 是用來記錄執行指令的時間,不同的 format 可以顯示不同的資訊,上面表示記錄 sleep 5 執行的時間及最大記憶體使用。

07. export QT_QPA_PLATFORM = offscreen,console 執行時就不會報錯。

08. $(shell command -v ls)

執行 command 查詢 ls 指令。

09. awk, mawk, gawk 三個是不同的程式

awk 'match($$0, pattern, array) 是錯的,因為這是 gawk 才有的語法,awk 有 match 但不能將 pattern 裡面抓到的 group 資訊存到 array。

2023年12月27日 星期三

iverilog + GTKWave 使用小技巧


這應該是我看過寫得最好的文章了。

除了教你如何 dump array,也教你如何儲存設定好的波形檔案(GTKWave -> File -> Write Save File As,假設檔名為 config.gtkw),下次啟動 GTKWave 就不用重拉了(gtkwave config.gtkw),這應該更有助於 debug。

後悔沒早看到這篇文章,只來得及儲存除法流水線範例設定檔。

2023年12月26日 星期二

Display verilog array built by iverilog in GTKWave

Ans:使用 generate 語法即可,generate for block 要不要命名都可以,這應該是目前最方便的 workaround 了。

`timescale 1ns/1ns
`define VIEW 1

module test;
    initial begin
        if (`VIEW == 1) begin
            $dumpfile("wave.vcd");
            $dumpvars(0, test);
        end
    end

    reg [3:0]  buffer[0:7];

    genvar j;
    generate
        for (j = 0; j < 8; j = j + 1) begin: buffer_array
            wire [3:0] buff;
            assign buff = buffer[j];
        end
    endgenerate

    integer i;
    initial begin
        for (i = 0; i < 8; i = i + 1) begin
            #10;
            buffer[i] = i[3:0];        
        end
        
        #200;
        $finish;    
    end
    
endmodule


2023/12/27 更新

還有另一個作法是使用 $dumpvars,這個似乎是 iverilog 作者在回網友郵件中建議的?這個語法更少,雖然 vpp 模擬時會有 warning,不過在 GTKwave 中不會多一個臨時變數,看起來更直觀,但似乎不是都可以用?請詳此處

module test;
    initial begin
        if (`VIEW == 1) begin
            $dumpfile("wave.vcd");
            $dumpvars(0, test);
            for (i = 0; i < 8; i = i + 1) begin
$dumpvars(1, test.buffer[i]);
    end
        end
    end

    reg [3:0]  buffer[0:7];