導航:首頁 > 源碼編譯 > jrop編譯

jrop編譯

發布時間:2023-01-12 01:19:12

編譯原理試題·

Lex和Yacc應用方法(一).初識Lex
草木瓜 20070301
Lex(Lexical Analyzar 詞法分析生成器),Yacc(Yet Another Compiler Compiler
編譯器代碼生成器)是Unix下十分重要的詞法分析,語法分析的工具。經常用於語言分
析,公式編譯等廣泛領域。遺憾的是網上中文資料介紹不是過於簡單,就是跳躍太大,
入門參考意義並不大。本文通過循序漸進的例子,從0開始了解掌握Lex和Yacc的用法。

一.Lex(Lexical Analyzar) 初步示例
先看簡單的例子(註:本文所有實例皆在RetHat linux下完成):
一個簡單的Lex文件 exfirst.l 內容:
%{
#include "stdio.h"
%}
%%
[\n] ;
[0-9]+ printf("Int : %s\n",yytext);
[0-9]*\.[0-9]+ printf("Float : %s\n",yytext);
[a-zA-Z][a-zA-Z0-9]* printf("Var : %s\n",yytext);
[\+\-\*\/\%] printf("Op : %s\n",yytext);
. printf("Unknown : %c\n",yytext[0]);
%%
命令行下執行命令flex解析,會自動生成lex.yy.c文件:
[root@localhost liweitest]flex exfirst.l
進行編譯生成parser可執行程序:
[root@localhost liweitest]cc -o parser lex.yy.c -ll
[注意:如果不加-ll鏈結選項,cc編譯時會出現以下錯誤,後面會進一步說明。]
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crt1.o(.text+0x18): In function `_start':
../sysdeps/i386/elf/start.S:77: undefined reference to `main'
/tmp/cciACkbX.o(.text+0x37b): In function `yylex':
: undefined reference to `yywrap'
/tmp/cciACkbX.o(.text+0xabd): In function `input':
: undefined reference to `yywrap'
collect2: ld returned 1 exit status

創建待解析的文件 file.txt:
title
i=1+3.9;
a3=909/6
bcd=4%9-333
通過已生成的可執行程序,進行文件解析。
[root@localhost liweitest]# ./parser < file.txt
Var : title
Var : i
Unknown : =
Int : 1
Op : +
Float : 3.9
Unknown : ;
Var : a3
Unknown : =
Int : 909
Op : /
Int : 6
Var : bcd
Unknown : =
Int : 4
Op : %
Int : 9
Op : -
Int : 333
到此Lex用法會有個直觀的了解:
1.定義Lex描述文件
2.通過lex,flex工具解析成lex.yy.c文件
3.使用cc編譯lex.yy.c生成可執行程序

再來看一個比較完整的Lex描述文件 exsec.l :

%{
#include "stdio.h"
int linenum;
%}
%%
title showtitle();
[\n] linenum++;
[0-9]+ printf("Int : %s\n",yytext);
[0-9]*\.[0-9]+ printf("Float : %s\n",yytext);
[a-zA-Z][a-zA-Z0-9]* printf("Var : %s\n",yytext);
[\+\-\*\/\%] printf("Op : %s\n",yytext);
. printf("Unknown : %c\n",yytext[0]);
%%
showtitle()
{
printf("----- Lex Example -----\n");
}
int main()
{
linenum=0;
yylex(); /* 進行分析 */
printf("\nLine Count: %d\n",linenum);
return 0;
}
int yywrap()
{
return 1;
}
進行解析編譯:
[root@localhost liweitest]flex exsec.l
[root@localhost liweitest]cc -o parser lex.yy.c
[root@localhost liweitest]./parser < file.txt
----- Lex Example -----
Var : i
Unknown : =
Int : 1
Op : +
Float : 3.9
Unknown : ;
Var : a3
Unknown : =
Int : 909
Op : /
Int : 6
Var : bcd
Unknown : =
Int : 4
Op : %
Int : 9
Op : -
Int : 333
Line Count: 4
這里就沒有加-ll選項,但是可以編譯通過。下面開始著重整理下Lex描述文件.l。

二.Lex(Lexical Analyzar) 描述文件的結構介紹
Lex工具是一種詞法分析程序生成器,它可以根據詞法規則說明書的要求來生成單詞識
別程序,由該程序識別出輸入文本中的各個單詞。一般可以分為<定義部分><規則部
分><用戶子程序部分>。其中規則部分是必須的,定義和用戶子程序部分是任選的。

(1)定義部分
定義部分起始於 %{ 符號,終止於 %} 符號,其間可以是包括include語句、聲明語句
在內的C語句。這部分跟普通C程序開頭沒什麼區別。
%{
#include "stdio.h"
int linenum;
%}
(2) 規則部分
規則部分起始於"%%"符號,終止於"%%"符號,其間則是詞法規則。詞法規則由模式和
動作兩部分組成。模式部分可以由任意的正則表達式組成,動作部分是由C語言語句組
成,這些語句用來對所匹配的模式進行相應處理。需要注意的是,lex將識別出來的單
詞存放在yytext[]字元數據中,因此該數組的內容就代表了所識別出來的單詞的內容。
類似yytext這些預定義的變數函數會隨著後面內容展開一一介紹。動作部分如果有多
行執行語句,也可以用{}括起來。
%%
title showtitle();
[\n] linenum++;
[0-9]+ printf("Int : %s\n",yytext);
[0-9]*\.[0-9]+ printf("Float : %s\n",yytext);
[a-zA-Z][a-zA-Z0-9]* printf("Var : %s\n",yytext);
[\+\-\*\/\%] printf("Op : %s\n",yytext);
. printf("Unknown : %c\n",yytext[0]);
%%
A.規則部分的正則表達式
規則部分是Lex描述文件中最為復雜的一部分,下面列出一些模式部分的正則表達式字
符含義:
A-Z, 0-9, a-z 構成模式部分的字元和數字。
- 指定范圍。例如:a-z 指從 a 到 z 之間的所有字元。
\ 轉義元字元。用來覆蓋字元在此表達式中定義的特殊意義,
只取字元的本身。

[] 表示一個字元集合。匹配括弧內的任意字元。如果第一個字
符是^那麼它表示否定模式。例如: [abC] 匹配 a, b, 和C
的任何一個。

^ 表示否定。
* 匹配0個或者多個上述模式。
+ 匹配1個或者多個上述模式。
? 匹配0個或1個上述模式。
$ 作為模式的最後一個字元時匹配一行的結尾。
{ } 表示一個模式可能出現的次數。 例如: A{1,3} 表示 A 可
能出現1次或3次。[a-z]{5} 表示長度為5的,由a-z組成的
字元。此外,還可以表示預定義的變數。

. 匹配任意字元,除了 \n。
( ) 將一系列常規表達式分組。如:{Letter}({Letter}|{Digit})*
| 表達式間的邏輯或。
"一些符號" 字元的字面含義。元字元具有。如:"*" 相當於 [\*]。
/ 向前匹配。如果在匹配的模式中的"/"後跟有後續表達式,
只匹配模版中"/"前面的部分。如:模式為 ABC/D 輸入 ABCD,
時ABC會匹配ABC/D,而D會匹配相應的模式。輸入ABCE的話,
ABCE就不會去匹配ABC/D。

B.規則部分的優先順序

規則部分具有優先順序的概念,先舉個簡單的例子:

%{
#include "stdio.h"
%}
%%
[\n] ;
A {printf("ONE\n");};
AA {printf("TWO\n");};
AAAA {printf("THREE\n");};
%%
此時,如果輸入內容:
[root@localhost liweitest]# cat file1.txt
AAAAAAA
[root@localhost liweitest]# ./parser < file1.txt
THREE
TWO
ONE
Lex分析詞法時,是逐個字元進行讀取,自上而下進行規則匹配的,讀取到第一個A字元
時,遍歷後發現三個規則皆匹配成功,Lex會繼續分析下去,讀至第五個字元時,發現
"AAAA"只有一個規則可用,即按行為進行處理,以此類推。可見Lex會選擇最長的字元
匹配規則。
如果將規則
AAAA {printf("THREE\n");};
改為
AAAAA {printf("THREE\n");};
./parser < file1.txt 輸出結果為:
THREE
TWO

再來一個特殊的例子:
%%
title showtitle();
[a-zA-Z][a-zA-Z0-9]* printf("Var : %s\n",yytext);
%%
並輸入title,Lex解析完後發現,仍然存在兩個規則,這時Lex只會選擇第一個規則,下面
的則被忽略的。這里就體現了Lex的順序優先順序。把這個例子稍微改一下:
%%
[a-zA-Z][a-zA-Z0-9]* printf("Var : %s\n",yytext);
title showtitle();
%%
Lex編譯時會提示:warning, rule cannot be matched.這時處理title字元時,匹配
到第一個規則後,第二個規則就無效了。
再把剛才第一個例子修改下,加深下印象!
%{
#include "stdio.h"
%}
%%
[\n] ;
A {printf("ONE\n");};
AA {printf("TWO\n");};
AAAA {printf("THREE\n");};
AAAA {printf("Cannot be executed!");};
./parser < file1.txt 顯示效果是一樣的,最後一項規則肯定是會忽略掉的。

C.規則部分的使用變數
且看下面示例:
%{
#include "stdio.h"
int linenum;
%}
int [0-9]+
float [0-9]*\.[0-9]+
%%
{int} printf("Int : %s\n",yytext);
{float} printf("Float : %s\n",yytext);
. printf("Unknown : %c\n",yytext[0]);
%%
在%}和%%之間,加入了一些類似變數的東西,注意是沒有;的,這表示int,float分
別代指特定的含義,在兩個%%之間,可以通過{int}{float}進行直接引用,簡化模
式定義。

(3) 用戶子程序部分
最後一個%%後面的內容是用戶子程序部分,可以包含用C語言編寫的子程序,而這些子
程序可以用在前面的動作中,這樣就可以達到簡化編程的目的。這里需要注意的是,
當編譯時不帶-ll選項時,是必須加入main函數和yywrap(yywrap將下後面說明)。如:
...
%%
showtitle()
{
printf("----- Lex Example -----\n");
}
int main()
{
linenum=0;
yylex(); /* 進行Lex分析 */
printf("\nLine Count: %d\n",linenum);
return 0;
}
int yywrap()
{
return 1;
}

三.Lex(Lexical Analyzar) 一些的內部變數和函數
內部預定義變數:
yytext char * 當前匹配的字元串
yyleng int 當前匹配的字元串長度
yyin FILE * lex當前的解析文件,默認為標准輸出
yyout FILE * lex解析後的輸出文件,默認為標准輸入
yylineno int 當前的行數信息
內部預定義宏:
ECHO #define ECHO fwrite(yytext, yyleng, 1, yyout) 也是未匹配字元的
默認動作

內部預定義的函數:
int yylex(void) 調用Lex進行詞法分析
int yywrap(void) 在文件(或輸入)的末尾調用。如果函數的返回值是1,就停止解
析。 因此它可以用來解析多個文件。代碼可以寫在第三段,這
樣可以解析多個文件。 方法是使用 yyin 文件指針指向不同的
文件,直到所有的文件都被解析。最後,yywrap() 可以返回1
來表示解析的結束。

lex和flex都是解析Lex文件的工具,用法相近,flex意為fast lexical analyzer generator。
可以看成lex的升級版本。

相關更多內容就需要參考flex的man手冊了,十分詳盡。

四.關於Lex的一些綜述
Lex其實就是詞法分析器,通過配置文件*.l,依據正則表達式逐字元去順序解析文件,
並動態更新內存的數據解析狀態。不過Lex只有狀態和狀態轉換能力。因為它沒有堆棧,
它不適合用於剖析外殼結構。而yacc增加了一個堆棧,並且能夠輕易處理像括弧這樣的
結構。Lex善長於模式匹配,如果有更多的運算要求就需要yacc了。

❷ 為啥自已編譯的op固件運行中斷 V21.02

固體運行沒有編譯正確。
op並且附帶3000左右的軟體包,用戶可以方便的自定義功能來製作固件。也可以方便的移植各類功能到openwrt下。
op固件是,經濟金融,企業管理,法律法規,社會民生,科學教育,健康生活,體育運動,文化藝術,電子數碼,電腦網路,娛樂休閑,行政地區,心理分析,醫療衛生,精選,知道專欄,知道日報,知道的大數據。

❸ 開篇:XLA是什麼

XLA (Accelerated Linear Algebra)是專用於機器學習的編譯器,機器學習的運算中99%都是向量乘以矩陣、矩陣乘以矩陣的計算,XLA是專門用來優化這些計算的。

舉個例子,運行在GPU上的 model_fn 函數會順序調用 multiply 、 add 和 rece_sum 這三個op,而且 multiply ,也就是 y * z 的計算結果會先從GPU拷貝回host,再拷貝到device作為 add 的input,同樣的,add的計算結果也會以相同的方式傳遞給下一個op。

顯然,對於整個函數來說,將中間變數在host和device間來回倒騰是沒有意義的。因此,如果把函數看作一個op,那在計算中產生的中間結果就不必返回到host,少了數據傳輸的時間開銷,就可以大幅提升運算效率。

這種將多個op融合成一個op的方法就稱為 fuse ,當前fuse的技術路線有:

XLA的優化當然不只是fuse,還有對計算圖的優化,包括刪除無效指令、減少內存佔用、替換復雜指令等優化。下圖是官方提供的性能報告,經XLA優化過後,Tensorflow BERT MLPerf的訓練性能提升了~7倍。除了Tensorflow外,XLA還支持 JAX 、 Julia 、 PyTorch 和 Nx 等前端。

jit 是指在首次運行時將函數編譯成二進製程序,後續再調用該函數時直接運行先前編譯好的程序而非python code。 @tf.funciton 修飾的函數(包括它的子函數)會做 jit 。除非signature發生了變化,也就是input的shape或dtype和編譯時不同,否則 get_MSE 是不需要重復編譯的。

@tf.function 將函數內的ops替換成一組( XlaCompile , XlaRun ) ops,在運行時前者負責編譯,並將編譯結果-- executable 保存到cache,後者負責運行executable。如果cache里已經有編譯好的程序就不需要編譯了,例如 get_MSE(tf.constant(3.0), tf.constant(4.0)) 。

XLA編譯器支持的語言(IR)是HLO(High Level Operations),顧名思義這些語言是由一個個op組成,因此,我們在編譯前需要先從python code中提取出所有ops,再將它們轉換成HLO。

JAX通過tracing的方式,從 @jax.jit 修飾的函數中提取ops,這些ops通過 jaxpr 來表示。然後再通過XLA client提供的API為ops生成相應的HLO。PyTorch/XLA也是採用類似的方法來生成HLO。

Tensorflow的 tf2xla 為每個 Op 創建了一個同名的 XlaOp 用於生成HLO, XlaOp 派生於 Op ,使用相同的注冊機制,因此,只要把要編譯的子圖根據拓撲排序運行一遍就能生成它的HLO。

HLO先經過一系列 pass 優化後再將HLO lowering成ISA,最後將編譯好的二進制封裝到 executable 。

除了二進製程序,它還包含運行該程序所需要的infos和options。調用 executable.run() 就可以執行計算圖。

❹ 求C語言文法及產生式!要做C編譯器——語法分析部分

轉自http://blog.csdn.net/rill_zhen/article/details/7701259http://blog.csdn.net/rill_zhen/article/details/7701259
希望能幫到你

編譯原理-1-C語言的文法
編譯原理-1-C語言的文法
c語言的文法產生式:
program ->
external_declaration
| program external_declaration
external_declaration ->
function_definition
| declaration
function_definition -> type_specifier declarator compound_statement
type_specifier ->
VOID
| CHAR
| INT
| FLOAT
declarator
pointer direct_declarator
| direct_declarator
Pointer->
'*'
| '*' pointer
direct_declarator
IDENTIFIER
|direct_declarator』[『 『]』
|direct_declarator 』[』 constant_expression 』]』
| IDENTIFIER '(' parameter_list ')'
| IDENTIFIER '(' ')'
|direct_declarator『,』identifier_list
identifier_list
: IDENTIFIER
| identifier_list ',' IDENTIFIER
constant_expression->
conditional_expression
parameter_list ->
parameter_declaration
| parameter_list ',' parameter_declaration

parameter_declaration ->
declaration_specifiers IDENTIFIER
compound_statement ->
'{' '}'
| '{' statement_list '}'
| '{' declaration_list statement_list '}'
declaration_list ->
declaration
| declaration_list declaration
Declaration->
init_declarator
| init_declarator_list ',' init_declarator
init_declarator ->
declarator
| declarator '=' initializer
Initializer ->
assignment_expression
| '{' initializer_list '}'
| '{' initializer_list ',' '}'
initializer_list ->
initializer
| initializer_list ',' initializer
statement_list->
statement
| statement_list statement
Statement ->
| compound_statement
| expression_statement
| selection_statement
| iteration_statement
| jump_statement
expression_statement ->
';'
| expression ';'
selection_statement
: IF '(' expression ')' statement
| IF '(' expression ')' statement ELSE statement
iteration_statement->
WHILE '(' expression ')' statement
| FOR '(' expression_statement expression_statement ')' statement
| FOR '(' expression_statement expression_statement expression ')' statement
jump_statement
| CONTINUE ';'
| BREAK ';'
| RETURN ';'
| RETURN expression ';'
expression
: assignment_expression
| expression ',' assignment_expression
assignment_expression ->
conditional_expression
| unary_expression assignment_operator assignment_expression
conditional_expression ->
logical_or_expression
| logical_or_expression ' ' expression ':' conditional_expression
logical_or_expression ->
logical_and_expression
| logical_or_expression OR_OP logical_and_expression
logical_and_expression
: inclusive_or_expression
| logical_and_expression AND_OP inclusive_or_expression
inclusive_or_expression->
exclusive_or_expression
| inclusive_or_expression '|' exclusive_or_expression
exclusive_or_expression
: and_expression
| exclusive_or_expression '^' and_expression
and_expression
: equality_expression
| and_expression '&' equality_expression
equality_expression
: relational_expression
| equality_expression EQ_OP relational_expression
| equality_expression NE_OP relational_expression
relational_expression
: shift_expression
| relational_expression '$amp;
| relational_expression '$amp;>apos;$ shift_expression
| relational_expression LE_OP shift_expression
| relational_expression GE_OP shift_expression
shift_expression
: additive_expression
| shift_expression LEFT_OP additive_expression
| shift_expression RIGHT_OP additive_expression
additive_expression
: multiplicative_expression
| additive_expression '+' multiplicative_expression
| additive_expression '-' multiplicative_expression
multiplicative_expression
: cast_expression
| multiplicative_expression '*' cast_expression
| multiplicative_expression '/' cast_expression
| multiplicative_expression '%' cast_expression
cast_expression
: unary_expression
| '(' type_name ')' cast_expression
unary_expression
: postfix_expression
| INC_OP unary_expression
| DEC_OP unary_expression
| unary_operator cast_expression
| SIZEOF unary_expression
| SIZEOF '(' type_name ')'
postfix_expression ->
: primary_expression
| postfix_expression '[' expression ']'
| postfix_expression '(' ')'
| postfix_expression '(' argument_expression_list ')'
| postfix_expression '.' IDENTIFIER
| postfix_expression PTR_OP IDENTIFIER
| postfix_expression INC_OP
| postfix_expression DEC_OP
primary_expression ->
IDENTIFIER
| CONSTANT
| STRING_LITERAL
| '(' expression ')'
argument_expression_list
: assignment_expression
| argument_expression_list ',' assignment_expression
unary_operator
: '&'
| '*'
| '+'
| '-'
| '~'
| '!'
assignment_operator ->
'='
| MUL_ASSIGN
| DIV_ASSIGN
| MOD_ASSIGN
| ADD_ASSIGN
| SUB_ASSIGN
| LEFT_ASSIGN
| RIGHT_ASSIGN
| AND_ASSIGN
| XOR_ASSIGN
| OR_ASSIGN
storage_class_specifier ->
TYPEDEF
| EXTERN
| STATIC
| AUTO
| REGISTER
struct_or_union_specifier
: struct_or_union IDENTIFIER '{' struct_declaration_list '}'
| struct_or_union '{' struct_declaration_list '}'
| struct_or_union IDENTIFIER
struct_or_union
: STRUCT
| UNION
struct_declaration_list
: struct_declaration
| struct_declaration_list struct_declaration
struct_declaration
: specifier_qualifier_list struct_declarator_list ';'
specifier_qualifier_list ->
type_specifier specifier_qualifier_list
| type_specifier
| type_qualifier specifier_qualifier_list
| type_qualifier
struct_declarator_list ->
struct_declarator
| struct_declarator_list ',' struct_declarator
struct_declarator ->
: declarator
| ':' constant_expression
| declarator ':' constant_expression
enum_specifier ->
ENUM '{' enumerator_list '}'
| ENUM IDENTIFIER '{' enumerator_list '}'
| ENUM IDENTIFIER
enumerator_list ->
enumerator
| enumerator_list ',' enumerator
Enumerator ->
IDENTIFIER
| IDENTIFIER '=' constant_expression
type_qualifier ->
CONST
| VOLATILE
type_qualifier_list ->
type_qualifier
| type_qualifier_list type_qualifier
parameter_type_list ->
parameter_list
| parameter_list ',' ELLIPSIS
parameter_list ->
: parameter_declaration
| parameter_list ',' parameter_declaration
type_name ->
specifier_qualifier_list
| specifier_qualifier_list abstract_declarator
abstract_declarator ->
pointer
| direct_abstract_declarator
| pointer direct_abstract_declarator
direct_abstract_declarator ->
'(' abstract_declarator ')'
| '[' ']'
| '[' constant_expression ']'
| direct_abstract_declarator '[' ']'
| direct_abstract_declarator '[' constant_expression ']'
| '(' ')'
| '(' parameter_type_list ')'
| direct_abstract_declarator '(' ')'
| direct_abstract_declarator '(' parameter_type_list ')'
labeled_statement ->
IDENTIFIER ':' statement
| CASE constant_expression ':' statement
| DEFAULT ':' statement

❺ 求教,在編譯環境里,op的wifi配置文件在哪個路徑

不建議修改源碼,還是新建一個files目錄,然後新增一個files/etc/config/wireless文件,編譯的時候會自動打包目錄

❻ 怎麼用C++編譯一個簡單的計算器

我借鑒了別人的某計算器,因為你沒有說多簡易...我就找了個差不多的...
/*
程序名稱:表達式計算器
編譯環境:Microsoft Visual C++ 6.0
作者:吉林大學 計算機科學與技術學院 2006 羅泗勇
時間:200801
*/

/*
說明:
採用樹形結構處理表達式,按優先順序運算結果,一個加,減,乘,除或數值為一個節點
優先順序如下:
函數:4
括弧:3
乘除:2
加減:1
*/

#include <windows.h>
#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
using namespace std;

const char NUM[]={'0','1','2','3','4','5','6','7','8','9','.'};
const char OPERATION[]={'+','-','*','/'};
const double PI=3.14159265358979;
const double EE=2.71828182818281;

class Fun //處理系統數學函數的類
{
public:
Fun(string o,int t,double l=0.0,double r=0.0):op(o),type(t),lvalue(l),rvalue(r){}
static string FUN[];
double calc();
private:
int type; //666 0 1 sin90 2 3! 3 3C2
string op; //函數類型
double lvalue; //函數左邊的值
double rvalue; //函數右邊的值
static int FunNum;
};

int Fun::FunNum=8;
string Fun::FUN[]={"!","sin","cos","tan","log","ln","C","A","^"};
/*
函數說明:
1:log是以10為底的工程對數
2:ln 是以e為底的自然對數
3:C 計算組合數 輸入規則 如計算 3取2的組合 輸入表達式 3C2
4:A 計算排列數 輸入規則 如計算 3取2的排列 輸入表達式 3A2
5:! 計算階乘
6:^ x的y次方 輸入 x^y
*/

int factorial(int n) //階乘函數
{
int i,s=1;
for(i=1;i<=n;i++)
s*=i;
return s;
}

int C(int a,int b)
{
return factorial(a)/(factorial(b)*factorial(a-b));
}

int A(int a,int b)
{
return factorial(a)/factorial(b);
}

double Fun::calc() //計算系統函數的值
{
if(type==0)
return lvalue;
else
{
if(op=="!")
return factorial(lvalue);
if(op=="sin")
return sin(rvalue/180*PI);
if(op=="cos")
return cos(rvalue/180*PI);
if(op=="tan")
return tan(rvalue/180*PI);
if(op=="log")
return log10(rvalue);
if(op=="ln")
return log10(rvalue)/log10(EE);
if(op=="C")
return C(lvalue,rvalue);
if(op=="A")
return A(lvalue,rvalue);
if(op=="^")
return pow(lvalue,rvalue);
else
{
string err="暫時沒有函數"+op;
MessageBox(NULL,err.c_str(),"錯誤",MB_OK);
return 0;
}
}
}

struct Unit //雙向鏈表保存運算單元
{
Unit(int p,char o,string c,double v,int t,Unit * pr=NULL,Unit * n=NULL)
:PRI(p),Operation(o),Code(c),value(v),Type(t),Pre(pr),Next(n){}
int PRI; //優先順序

char Operation; //操作符
string Code; //原始代碼
double value; //數據

int Type; //類型 操作符0 數據1 函數2
Unit * Pre; //構成雙向鏈表
Unit * Next;
};

class Node //表達式樹狀結構的節點
{
public:
Node(char o,int p,int e=1,double v=0,Node * ph=NULL,Node * pl=NULL,Node * pr=NULL)
:Operation(o),PRI(p),Expression(e),value(v),Head(ph),Left(pl),Right(pr){}
Node * Head; //節點的根,左樹枝,右樹枝
Node * Left;
Node * Right;
double GetValue();
char GetOperation() const {return Operation;}
int GetPri() const {return PRI;}
int IsExp() const {return Expression;}
private:
char Operation; //操作符
int PRI; //優先順序
int Expression; //記錄該節點是否是表達式0 1
double value; //該節點的值
};

double Node::GetValue() //運算該節點的值
{
if(IsExp()) //該節點的值還未算出來
{
double lvalue,rvalue;
lvalue=Left->GetValue();
rvalue=Right->GetValue();
Expression=0;
char op=GetOperation();
switch(op)
{
case '+':
return lvalue+rvalue;
case '-':
return lvalue-rvalue;
case '*':
return lvalue*rvalue;
case '/':
return lvalue/rvalue;
default:
return 0;
}
}
else
return value;
}

bool Isnum(char c)
{
for(int i=0;i<sizeof(NUM);i++)
{
if(c==NUM[i])
return true;
}
return false;
}

bool Isoperation(char c)
{
for(int i=0;i<sizeof(OPERATION);i++)
{
if(c==OPERATION[i])
return true;
}
return false;
}

Unit * Analyse(string exp) //分析表達式並生成鏈表
{
int pri=0; //當前優先順序
int stat=-1; //當前的讀入狀態 括弧 0 數據 1 運算符 2
Unit * head=NULL,* p=NULL;
int i=0,explen;
explen=exp.size();
for(i=0;i<explen;i++)
{
char c=exp.at(i);
if(c=='(')
{
pri+=3;
stat=0;
}
else if(c==')')
{
pri-=3;
stat=0;
}
else if(Isoperation(c)) //操作符不會出現在表達式開頭
{
Unit * temp=p;
int add_pri; //自身增加的優先順序
if(c=='+' || c=='-')
add_pri=1;
else
add_pri=2;
p->Next=new Unit(pri+add_pri,c," ",0,0);
p=p->Next;
p->Pre=temp;
}
else //其他的當做函數處理
{
string function="";
while(i<explen && (c=exp.at(i),! Isoperation(c)) && c!=')')
{
function+=c;
i++;
}
i--;

if(head==NULL)
{
p=new Unit(pri,' ',function,0,2);
head=p;
}
else
{
Unit * temp=p;
p->Next=new Unit(pri,' ',function,0,2);
p=p->Next;
p->Pre=temp;
}
}
}
return head;
}

Unit * Calc(Unit * head) //計算雙向鏈表基本單元的值
{
Unit * p=head;
while(p!=NULL)
{
if(p->Type!=0) //非操作符
{
string temp=p->Code;
string op;
double lvalue=0,rvalue=0;
int l_point=0,r_point=0;
int i=0,type=0;
char ch;
while(i<temp.size() && (ch=temp.at(i),Isnum(ch)))
{
if(ch=='.')
{
l_point++;
i++;
continue;
}
if(! l_point)
lvalue*=10;
lvalue+=(ch-'0')*pow(10,-l_point);
i++;
if(l_point)
l_point++;
}
while(i<temp.size() && (ch=temp.at(i),! Isnum(ch)))
{
op+=ch;
type=1;
i++;
}
while(i<temp.size() && (ch=temp.at(i),Isnum(ch)))
{
if(ch=='.')
{
r_point++;
i++;
continue;
}
if(! r_point)
rvalue*=10;
rvalue+=(ch-'0')*pow(10,-r_point);
i++;
if(r_point)
r_point++;
}
Fun * f=new Fun(op,type,lvalue,rvalue);
p->value=f->calc();
}
p=p->Next;
}
return head;
}

Node * Tree(Unit * head) //生成表達式樹
{
Node * root=NULL,* proot=NULL,* pbranch=NULL;
Unit * p=head;
int now_pri; //當前優先順序
bool hadop=false;
while(p!=NULL)
{
if(p->Type==0) //如果是一個操作符
{
hadop=true;
if(root==NULL)
{
proot=new Node(p->Operation,p->PRI,1);
root=proot;
pbranch=root;
now_pri=p->PRI;
proot->Left=new Node(' ',0,0,p->Pre->value);
proot->Right=new Node(' ',0,0,p->Next->value);
}
else
{
if(p->PRI<=now_pri) //優先順序低於當前優先順序,樹根方向 //最初寫的 if(p->PRI<now_pri),9/3/3=9,錯的
{
proot=new Node(p->Operation,p->PRI,1); //新的樹根
proot->Left=root; //根的變換
proot->Right=new Node(' ',0,0,p->Next->value);
root=proot;

pbranch=proot; //右樹枝的變換
//pbranch->Right=new Node(' ',0,0,p->Pre->value); //樹枝右邊取值
}
else
{
Node * temp;
temp=new Node(p->Operation,p->PRI,1);

pbranch->Right=temp;
temp->Head=pbranch;

pbranch=pbranch->Right;
pbranch->Left=new Node(' ',0,0,p->Pre->value);
pbranch->Right=new Node(' ',0,0,p->Next->value);
}
now_pri=p->PRI;
}
}
p=p->Next;
}
if(! hadop)
root=new Node(' ',0,0,head->value);
return root;
}

int main()
{
string exp;

//ifstream infile("test.txt",ios::in);
while(! getline(cin,exp).eof())
{
if(exp=="")
continue;
Unit * h=Analyse(exp);
h=Calc(h);
Node * root=Tree(h);
cout<<exp<<"="<<root->GetValue()<<endl;
}
return 0;
}

❼ 編譯原理 四元式

四元式是一種比較普遍採用的中間代碼形式。

代碼段的四元式表達式:

101 T:=0 (表達式為假的出口)

103 T:=1 (表達式為真的出口)

因為用戶的表達式只有一個A<B,因此A<B的真假出口就是表達式的真假出口,所以

100: if a<b goto 103 (a<b為真,跳到真出口103)

101: T:=0(否則,進入假出口)

102: goto 104 (要跳過真出口,否則T的值不就又進入真出口了,為真)

103: T:=1

104:(程序繼續執行)

(7)jrop編譯擴展閱讀:

四元式是一種更接近目標代碼的中間代碼形式。由於這種形式的中間代碼便於優化處理,因此,在目前許多編譯程序中得到了廣泛的應用。

四元式實際上是一種「三地址語句」的等價表示。它的一般形式為:

(op,arg1,arg2,result)

其中, op為一個二元 (也可是一元或零元)運算符;arg1,arg2分別為它的兩個運算 (或操作)對象,它們可以是變數、常數或系統定義的臨時變數名;運算的結果將放入result中。四元式還可寫為類似於PASCAL語言賦值語句的形式:

result ∶= arg1 op arg2

需要指出的是,每個四元式只能有一個運算符,所以,一個復雜的表達式須由多個四元式構成的序列來表示。例如,表達式A+B*C可寫為序列

T1∶=B*C

T2∶=A+T1

其中,T1,T2是編譯系統所產生的臨時變數名。當op為一元、零元運算符 (如無條件轉移)時,arg2甚至arg1應預設,即result∶=op arg1或 op result ;對應的一般形式為:

(op,arg1,,result)

(op,,,result)

❽ JIT(上):Tensorflow如何實現即時編譯

Tensorflow的JIT(just-in-time)是指在運行 @tf.function 修飾的python函數時,由 jit 、 tf2xla 和 XLA 一起完成一系列如子圖構造、子圖優化、圖編譯和圖執行等操作。編譯後的可執行程序-- executable 會存放到cache中,供再次調用時直接獲取執行。JIT的好處在 開篇 已經講過了,這里不再贅述。

JIT的流程可以概括為:Tensorflow子圖構造/優化,graph -> HLO,編譯/執行,合並計算結果到Tensorflow圖這四部分。本文只涉及圖編譯和圖執行。

函數中ops在子圖構造階段被包裹進一個cluster node,並替換成 xla_compile 和 xla_run 這兩op,而 XlaCompileOp 和 XlaRunOp 就是它們的 OpKernel ,分別用於圖編譯和執行。

XlaCompileOp通過 XlaCompilationCache 獲取或編譯executable,並將其封裝成 XlaExecutableClosure ,並緩存在 XlaExecutableClosureStore 。 XlaRunOp 用從XlaCompileOp傳遞來的key在cache中查找並執行executable。

從編譯流程圖可以看到,XLA的編譯結果會緩存到XlaCompilationCache,後續調用可以根據 signature 在cache中查找executable。

函數的 signature 是由 BuildSignature(function, args) 根據函數和arguments生成的。即使是同一個函數,只要input tensors不同,signature也會不一樣,這就是 power() 被編譯兩次的原因:第三次函數調用時,由於無法通過signature在cache中找到executable而觸發編譯。

signature表示唯一的計算圖:只要函數中的ops序列和arguments(type/shape)是確定的,那麼計算圖也是確定的。

編譯之前需要通過 tf2xla 將圖轉換成XLA支持的語言 HLO 。tf2xla為每個Tensorflow op創建了生成HLO的 XlaOp ,因此,只要執行該Tensorflow子圖,就可以生成具有相同的拓撲排序的HLO -- XlaComputation 。

XlaComputation (HLO)可以認為是一個運行在device上的純函數,它的input/output會伴隨著host-to-device(H2D)和device-to-host(D2H)的數據傳輸。

我們知道,Tensorflow圖中的input tensor有兩種: tf.Placeholder 和 tf.Variable ,前者每個step都會將新data發送到device,而後者是模型參數,它們會常駐內存,只在store/load checkpoint才會有H2D/D2H。

而純函數的定義是:

不管是input還是output,雖然variable和其他argument一樣存在於HLO的參數列表和返回值列表中,但它們實際上是常駐於device的,不需要也不應該H2D/D2H。

因此,HLO在編譯時還需要通過 argument_input_indices 、 resource_input_indices 和 resource_update_to_input_index 等options來區分arguments和variables。

此外,如果有input是常數,為了避免無謂的H2D開銷,可以把它固化到函數內部。同理,對於常數output,它沒必要出現在函數中,可以直接定義在 XlaCompilationResult 的output buffer。

XlaCompilationResult是 Graph -> HLO 的output,它封裝了HLO以及上述部分metadata、buffers。

XlaCompileOp會把編譯好的executable、metadata、input/output buffers、options等統統封裝進一個closure -- XlaExecutableClosure ,並將其緩存在 XlaExecutableClosureStore 供 XlaRunOp 獲取。

XlaRunOp 可以通過一個數字字元串key(從0開始累加)從cache中查找並執行XlaExecutableClosure,這個key由XlaCompileOp提供。

❾ 有人知道編譯原理實驗之詞法分析器用C++怎麼做嗎

#include "globals.h"
#include "util.h"
#include "scan.h"
#include "parse.h"

static TokenType token; /* holds current token */

/* function prototypes for recursive calls */
static TreeNode * stmt_sequence(void);
static TreeNode * statement(void);
static TreeNode * if_stmt(void);
static TreeNode * repeat_stmt(void);
static TreeNode * assign_stmt(void);
static TreeNode * read_stmt(void);
static TreeNode * write_stmt(void);
static TreeNode * exp(void);
static TreeNode * simple_exp(void);
static TreeNode * term(void);
static TreeNode * factor(void);

static void syntaxError(char * message)
{ fprintf(listing,"\n>>> ");
fprintf(listing,"Syntax error at line %d: %s",lineno,message);
Error = TRUE;
}

static void match(TokenType expected)
{ if (token == expected) token = getToken();
else {
syntaxError("unexpected token -> ");
printToken(token,tokenString);
fprintf(listing," ");
}
}

TreeNode * stmt_sequence(void)
{ TreeNode * t = statement();
TreeNode * p = t;
while ((token!=ENDFILE) && (token!=END) &&
(token!=ELSE) && (token!=UNTIL))
{ TreeNode * q;
match(SEMI);
q = statement();
if (q!=NULL) {
if (t==NULL) t = p = q;
else /* now p cannot be NULL either */
{ p->sibling = q;
p = q;
}
}
}
return t;
}

TreeNode * statement(void)
{ TreeNode * t = NULL;
switch (token) {
case IF : t = if_stmt(); break;
case REPEAT : t = repeat_stmt(); break;
case ID : t = assign_stmt(); break;
case READ : t = read_stmt(); break;
case WRITE : t = write_stmt(); break;
default : syntaxError("unexpected token -> ");
printToken(token,tokenString);
token = getToken();
break;
} /* end case */
return t;
}

TreeNode * if_stmt(void)
{ TreeNode * t = newStmtNode(IfK);
match(IF);
if (t!=NULL) t->child[0] = exp();
match(THEN);
if (t!=NULL) t->child[1] = stmt_sequence();
if (token==ELSE) {
match(ELSE);
if (t!=NULL) t->child[2] = stmt_sequence();
}
match(END);
return t;
}

TreeNode * repeat_stmt(void)
{ TreeNode * t = newStmtNode(RepeatK);
match(REPEAT);
if (t!=NULL) t->child[0] = stmt_sequence();
match(UNTIL);
if (t!=NULL) t->child[1] = exp();
return t;
}

TreeNode * assign_stmt(void)
{ TreeNode * t = newStmtNode(AssignK);
if ((t!=NULL) && (token==ID))
t->attr.name = String(tokenString);
match(ID);
match(ASSIGN);
if (t!=NULL) t->child[0] = exp();
return t;
}

TreeNode * read_stmt(void)
{ TreeNode * t = newStmtNode(ReadK);
match(READ);
if ((t!=NULL) && (token==ID))
t->attr.name = String(tokenString);
match(ID);
return t;
}

TreeNode * write_stmt(void)
{ TreeNode * t = newStmtNode(WriteK);
match(WRITE);
if (t!=NULL) t->child[0] = exp();
return t;
}

TreeNode * exp(void)
{ TreeNode * t = simple_exp();
if ((token==LT)||(token==EQ)) {
TreeNode * p = newExpNode(OpK);
if (p!=NULL) {
p->child[0] = t;
p->attr.op = token;
t = p;
}
match(token);
if (t!=NULL)
t->child[1] = simple_exp();
}
return t;
}

TreeNode * simple_exp(void)
{ TreeNode * t = term();
while ((token==PLUS)||(token==MINUS))
{ TreeNode * p = newExpNode(OpK);
if (p!=NULL) {
p->child[0] = t;
p->attr.op = token;
t = p;
match(token);
t->child[1] = term();
}
}
return t;
}

TreeNode * term(void)
{ TreeNode * t = factor();
while ((token==TIMES)||(token==OVER))
{ TreeNode * p = newExpNode(OpK);
if (p!=NULL) {
p->child[0] = t;
p->attr.op = token;
t = p;
match(token);
p->child[1] = factor();
}
}
return t;
}

TreeNode * factor(void)
{ TreeNode * t = NULL;
switch (token) {
case NUM :
t = newExpNode(ConstK);
if ((t!=NULL) && (token==NUM))
t->attr.val = atoi(tokenString);
match(NUM);
break;
case ID :
t = newExpNode(IdK);
if ((t!=NULL) && (token==ID))
t->attr.name = String(tokenString);
match(ID);
break;
case LPAREN :
match(LPAREN);
t = exp();
match(RPAREN);
break;
default:
syntaxError("unexpected token -> ");
printToken(token,tokenString);
token = getToken();
break;
}
return t;
}

/****************************************/
/* the primary function of the parser */
/****************************************/
/* Function parse returns the newly
* constructed syntax tree
*/
TreeNode * parse(void)
{ TreeNode * t;
token = getToken();
t = stmt_sequence();
if (token!=ENDFILE)
syntaxError("Code ends before file\n");
return t;
}
上面是一個語法分析器的主代碼部分它可以識別類似下面的代碼,但是由於篇幅有限,上面的代碼不是完整代碼,完整代碼太長,還有好幾個文件。
read x; { input an integer }
if 0 < x then { don't compute if x <= 0 }
fact := 1;
repeat
fact := fact * x;
x := x - 1
until x = 0;
write fact { output factorial of x }
end

閱讀全文

與jrop編譯相關的資料

熱點內容
南通住房公積金app支取銀行怎麼填 瀏覽:679
韓國劇情電影男主自殺2次是什麼電影 瀏覽:644
李彩譚電影全部 瀏覽:702
范偉喬杉電影叫什麼名字 瀏覽:467
中國十大免費電影網站 瀏覽:509
一富豪請兩個女的的電影 瀏覽:700
如何雲伺服器搭建游戲 瀏覽:561
魔獸獵人宏命令 瀏覽:433
翁虹電影大全 瀏覽:990
如何把文件夾改變為安裝包 瀏覽:299
地震勘探pdf 瀏覽:690
c語言怎樣給字元串加密 瀏覽:583
什麼網站可以看劇情 瀏覽:533
cad圖紙空間命令 瀏覽:136
GRA26K 瀏覽:479
單片機stm32實驗心得體會 瀏覽:618
php壓縮包如何安裝 瀏覽:647
免費看慢網站 瀏覽:151
外國影片女孩頭一次出去上外地 瀏覽:479
程序員創業接到小程序訂單 瀏覽:392