Categories
不学无术

Python如何遍历一个文件夹下的所有文件

import glob
fileList=glob.glob(“E:PythonWork*.exe”)
for filename in fileList:
带参数调用filename
 
 
source:
http://bbs.csdn.net/topics/90198608

Categories
不学无术

Lex与Yacc快速入门

附件:Yacc与Lex快速入门
http://orz.dayandcarrot.net/wordpress/wp-content/uploads/2013/05/Yacc与Lex快速入门.pdf
 
Lex 和 Yacc 是 UNIX 两个非常重要的、功能强大的工具。事实上,如果你熟练掌握
Lex 和 Yacc 的话,它们的强大功能使创建 FORTRAN 和 C 的编译器如同儿戏。
Ashish Bansal 为您详细的讨论了编写自己的语言和编译器所用到的这两种工具,包
括常规表达式、声明、匹配模式、变量、Yacc 语法和解析器代码。最后,他解释了
怎样把 Lex 和 Yacc 结合起来。
详见附件

Categories
不学无术

词法分析:如何将NFA转换为DFA

  • 本文来源及参考资料:
  1. http://hi.baidu.com/beanchx/item/b153390de0691827a1312d49
  2. http://www.2cto.com/kf/201302/191521.html
  3. http://dev.21tx.com/2009/09/26/11354.html

 1. 子集构造(Subset Construction)

这是一个转换NFA到DFA的算法。我们知道NFA和DFA的区别最主要的就是一个状态和一个input symbol是否能够确定一个状态的问题,对于NFA,它将确定一个组状态,而DFA将确定一个状态,因此,我们有一个很好的办法就是把NFA的状态集对应每个DFA的状态,这就是subset construction的思想,不过这只是大概泛泛而论,我们需要更加明确的认识
1) NFA在任何一个input symbol下,映射的状态集(通过move函数,这个集合通常用T字母表示)应该被知道
2) 必须保证1)中状态集都对应了DFA中的一个状态

  具体算法:

Input : 一个NFA N
Output : 接受相同语言的DFA D
Method : 为D构架一个transition table(转换表) Dtran,每个DFA的状态是一个NFA的状态集合(这里一定要注意前面说过的1)2)两点)。我们定义一些操作:
s 表示NFA的状态,T 表示NFA的状态集合,a表示一个input symbol
ε-transition(ε转换)就是说input symbol为ε时的transition(转换)
 

操作(operation)
 
描述(description)
 
ε-closure(s)
 
从NFA的状态s出发,只通过ε-transition到达的NFA的状态集合
 
ε-closure(T)
 
NFA的集合T中的状态p,只通过ε-transition到达的NFA的状态集合,再求这些集合的交集。用数学表达就是 {p|p 属于 ε-closure(t) , t属于T}
 
move(T,a)
 
NFA的集合,这个集合在input symbol为a,状态为T中任意状态情况下,通过一个转换得到的集合
 

 
注意一下,所有的操作都是针对NFA的状态或者状态集合,得到的时NFA的状态集合,或者说是DFA看为一个状态
Subset Construction
初始Dstates,它仅仅含有状态(D的状态)ε-closure(s0),并且状态未被标记,s0表示开始状态,注意,Dstates放的是D的状态
while ( Dstates 有未标记的状态 T ) { // T是D中的一个状态,也是N中一个状态集
标记 T;
for ( input symbol a ){                  // 遍历所有的input symbol
U = ε-closure(move(T, a));        // move为NFA的move函数
if ( U 不在 Dstates 中 )
把U作为尚未标记的状态加入Dstates;
Dtran[T, a] = U
}
}

注意,状态s,ε-closure(s)一定包含s
我们先来熟悉上面的操作operation,再来看上面的算法
词法分析(4)---NFA与DFA的转化
ε-closure(0) = {0, 1, 2, 4, 7}   // 从0状态出发的,input symbol为ε的所有状态的集合
ε-closure(3) = {1, 2, 3, 4, 6, 7}
ε-closure(8) = {8}
ε-closure( {3, 8} ) = ε-closure(3) U ε-closure(8) = {1, 2, 3, 4, 6, 7, 8}
move(0,a) = 空
move(7,a) = {8}
move(8,b) = {9}
move( {0, 1, 2, 4, 7}, a) = move(0,a) U move(1,a) U move(2,a) U move(4,a) U move(7,a) = {3, 8}

现在可以回去理解一下算法了。
这里再说说求ε-closure(T)的算法:
把T的所有状态压入stack(栈);
ε-closure(T)的初始值为 T 中的所有元素 ;  // 也就是一定包含他们本身
while( 栈非空 ) {
弹出栈顶元素 t ;
for( 每个属于 move(t, ε) 的状态 u ){
if( u 不在 ε-closure(T) 中 ){
u 加入 ε-closure(T);
把 u 入栈;
}
}
}

下面对上图如何使用Set Construction算法来构建DFA做一个详细的描述:
1. 初始化Dstates 把集合 ε-closure(s0) = {0, 1, 2, 4, 7}作为第一个状态,设此状态为 A
2. 现在转化,input symbol {a, b},因此,求:
ε-closure(move(A, a));
ε-closure(move(A, b));
这里会得到2个状态
ε-closure(move(A, a)) = {1, 2, 3, 4, 6, 7, 8},设其为 B
ε-closure(move(A, b)) = {1, 2, 4, 5, 6, 7}, 设其为C
B,C放入Dstates
改写 Dtrans
最终得到的 Dtrans 为:
A = {0, 1, 2, 4, 7}
B = {1, 2, 3, 4, 6, 7, 8}
C = {1, 2, 4, 5, 6, 7}
D = {1, 2, 4, 5, 6, 7, 9}
词法分析(4)---NFA与DFA的转化
因此,NFA转化成为DFA:
词法分析(4)---NFA与DFA的转化
 
=========================================
DFA的状态

在DFA中,某个状态对应到ε-NFA中的若干状态,应此我们将会得到下面这样的一个结构。
struct DFA_State
        {
            set content;
            bool                   bFlag;
#ifdef _DEBUG
            uint                   idx;
#endif
            DFA_State(const set& x) : content(x), bFlag(false)
            {
#ifdef _DEBUG
                idx = inc();
#endif
            }
            inline const bool operator==(const DFA_State& x)const
            {
                if (&x == this) return true;
                return content == x.content;
            }
#ifdef _DEBUG
            inline uint inc()
            {
                static uint i = 0;
                return i++;
            }
#endif
        };
可以看到,为了调试方便我们在结构中定义了状态的唯一ID以及对应到ε-NFA状态的集合和一个标记位。
DFA的边
根据上一篇的经验,不难想到DFA的边应该是什么样的,下面直接给出代码,不做说明。
  struct DFA_Edge
        {
            struct
            {
                Char_Type   char_value;
                String_Type string_value;
            }data;
            enum Edge_Type
            {
                TUnknown = 0,
                TNot     = 1,
                TChar    = 2,
                TString  = 4
            };
            uchar edge_type;
            DFA_State* pFrom;
            DFA_State* pTo;
            DFA_Edge(const Char_Type& x, bool bNot, DFA_State* pFrom, DFA_State* pTo) : pFrom(pFrom), pTo(pTo)
            {
                data.char_value = x;
                edge_type = bNot ? (TChar | TNot) : TChar;
            }
            DFA_Edge(const String_Type& x, bool bNot, DFA_State* pFrom, DFA_State* pTo) : pFrom(pFrom), pTo(pTo)
            {
                data.string_value = x;
                edge_type = bNot ? (TString | TNot) : TString;
            }
            inline const bool isNot()const
            {
                return (edge_type & TNot) == TNot;
            }
            inline const bool isChar()const
            {
                return (edge_type & TChar) == TChar;
            }
            inline const bool isString()const
            {
                return (edge_type & TString) == TString;
            }
            const Edge_Type edgeType()const
            {
                if (isChar()) return TChar;
                else if (isString()) return TString;
                else return TUnknown;
            }
            const bool operator<(const DFA_Edge& x)const
            {
                return (ulong)pFrom + pTo < (ulong)x.pFrom + x.pTo;
            }
            const bool operator==(const DFA_Edge& x)const
            {
                return pFrom == x.pFrom && pTo == x.pTo;
            }
        };
由于DFA中不存在ε边,应此DFA将会存在若干个结束状态,但他只有一个开始状态
DFA_State*      pDFAStart;
set pDFAEnds;
set   dfa_Edges;
为了下一步分析的高效,以后可能会将这里的dfa_Edges同样修改为hashmap。
至此DFA所要用到的两个结构迅速的介绍完了。
子集构造算法
通过各种资料,我们不难发现,从ε-NFA转换到DFA的过程中,最常用就是子集构造算法。子集构造算法的主要思想是让DFA的每个状态对应NFA的一个状态集。这个DFA用它的状态去记住NFA在读输入符号后达到的所有状态。(引自编译原理)其算法如下
输入:一个NFA N。
输出:一个接受同样语言的DFA D。
方法:
1.求取ε-NFA初始状态的ε闭包作为DFA的起始状态,并将这个状态加入集合C中,且它是未标记的。同时记录它的向后字符集。
2.从集合C中取出一个未被标记的子集T和其对应的字符集,标记子集T。
3.使用上一步取出的字符集通过状态转移函数求出转移后的状态集M。
4.求取上一步得到的状态集M的ε闭包U
5.如果U不在集合C中则将U作为未被标记的子集加入C中,同时记录它的向后字符集。检查状态U中是否存在NFA中的终结状态,若存在则将状态U加入到pDFAEnds中。
重复2,3,4,5部直至集合C中不存在未被标记的状态。
ε闭包
ε闭包是指从某个状态起只经过ε边达到的其他状态的集合,同时这个状态也属于这个集合中。其算法如下
输入:状态集k。
输出:状态集U和其所对应的向后字符集。
方法:
1.遍历状态集k中的每个状态k'。
2.若k'不存在于结果状态集U中,将k'插入U中。
3.建立一个临时集合tmp,并将k'插入其中。
4.从临时集合tmp中取出一个状态p。
5.取出所有从p出发的边,若这条边是ε边,且抵达状态不在结果状态集U中,将抵达的状态分别插入结果状态集U和临时集合tmp中。若这条边是字符集的边且这条边所对应的字符不在向后字符集中,则将向后字符插入向后字符集中。
6.将状态p从临时集合tmp中删除。
循环4,5,6部直至tmp中不存在任何状态为止。
由于在生成ε-NFA时不存在只有ε边的循环,应此这里不会产生死循环。下面给出具体的代码
  void epsilonClosure(const set& k, EpsilonClosureInfo& info)
        {
            for (typename set::const_iterator i = k.begin(), m = k.end(); i != m; ++i)
            {
                info.states.insert(*i);
                set tmp;
                tmp.insert(*i);
                while (!tmp.empty())
                {
                    EpsilonNFA_State* pState = *tmp.begin();
                    for (typename vector::const_iterator j = epsilonNFA_Edges[pState].begin(), n = epsilonNFA_Edges[pState].end(); j != n; ++j)
                    {
                        if (j->isEpsilon())
                        {
                            if (info.states.insert(j->pTo).second) tmp.insert(j->pTo);
                        }
                        else if (j->isChar()) info.chars.insert(pair(j->data.char_value, j->isNot()));
                        else if (j->isString()) info.strings.insert(pair(j->data.string_value, j->isNot()));
                    }
                    tmp.erase(pState);
                }
            }
        }
其中用到的EpsilonClosureInfo结构为
  struct EpsilonClosureInfo
        {
            set        states;
            set >   chars;
            set > strings;
            EpsilonClosureInfo() {}
            EpsilonClosureInfo(const set& states,
                               const set >& chars,
                               const set >& strings)
                               : states(states)
                               , chars(chars)
                               , strings(strings) {}
            EpsilonClosureInfo(const EpsilonClosureInfo& x)
            {
                states  = x.states;
                chars   = x.chars;
                strings = x.strings;
            }
        };
需要保存的是状态集和向后字符集。
状态转移函数
通过状态转移函数,输入一个集合T和一个字符a将可得到所有通过T中的每一个状态和a边所能达到的状态的集合。应此代码如下
   set move(const DFA_State& t, const Char_Type& c, bool bNot)
        {
            set result;
            for (typename set::const_iterator i = t.content.begin(), m = t.content.end(); i != m; ++i)
            {
                for (typename vector::const_iterator j = epsilonNFA_Edges[*i].begin(), n = epsilonNFA_Edges[*i].end(); j != n; ++j)
                {
                    if (j->isChar() && j->data.char_value == c && j->isNot() == bNot) result.insert(j->pTo);
                }
            }
            return result;
        }
        set move(const DFA_State& t, const String_Type& s, bool bNot)
        {
            set result;
            for (typename set::const_iterator i = t.content.begin(), m = t.content.end(); i != m; ++i)
            {
                for (typename vector::const_iterator j = epsilonNFA_Edges[*i].begin(), n = epsilonNFA_Edges[*i].end(); j != n; ++j)
                {
                    if (j->isString() && j->data.string_value == s && j->isNot() == bNot) result.insert(j->pTo);
                }
            }
            return result;
        }
为了分别支持Char_Type和String_Type的字符我们定义了两个move函数。
最后我们给出子集构造算法的代码
   void buildDFA()
        {
            set start;
            start.insert(pEpsilonStart);
            typedef pair c_type;
            map > c;
            queue c2;
            pDFAStart = DFA_State_Alloc::allocate();
            EpsilonClosureInfo info;
            epsilonClosure(start, info);
            construct(pDFAStart, info.states);
            c_type ct(pDFAStart, info);
            c[info.states.size()].push_back(ct);
            c2.push(ct);
            if (isEndDFAStatus(pDFAStart)) pDFAEnds.insert(pDFAStart);
            context.dfa_States.insert(pDFAStart);
            while (!c2.empty())
            {
                DFA_State* t = c2.front().first;
                set > chars = c2.front().second.chars;
                set > strings = c2.front().second.strings;
                t->bFlag = true;
                for (typename set >::const_iterator i = chars.begin(), m = chars.end(); i != m; ++i)
                {
                    EpsilonClosureInfo info;
                    epsilonClosure(move(*t, i->first, i->second), info);
                    DFA_State* p = getDFAState(info.states, c);
                    if (p) // 如果这个状态已存在
                    {
                        dfa_Edges.insert(DFA_Edge(i->first, i->second, t, p));
                    }
                    else
                    {
                        DFA_State* pState = DFA_State_Alloc::allocate();
                        construct(pState, info.states);
                        context.dfa_States.insert(pState);
                        if (isEndDFAStatus(pState)) pDFAEnds.insert(pState);
                        c_type ct(pState, info);
                        c[info.states.size()].push_back(ct);
                        c2.push(ct);
                        dfa_Edges.insert(DFA_Edge(i->first, i->second, t, pState));
                    }
                }
                for (typename set >::const_iterator i = strings.begin(), m = strings.end(); i != m; ++i)
                {
                    EpsilonClosureInfo info;
                    epsilonClosure(move(*t, i->first, i->second), info);
                    DFA_State* p = getDFAState(info.states, c);
                    if (p) // 如果这个状态已存在
                    {
                        dfa_Edges.insert(DFA_Edge(i->first, i->second, t, p));
                    }
                    else
                    {
                        DFA_State* pState = DFA_State_Alloc::allocate();
                        construct(pState, info.states);
                        context.dfa_States.insert(pState);
                        if (isEndDFAStatus(pState)) pDFAEnds.insert(pState);
                        c_type ct(pState, info);
                        c[info.states.size()].push_back(ct);
                        c2.push(ct);
                        dfa_Edges.insert(DFA_Edge(i->first, i->second, t, pState));
                    }
                }
                c2.pop();
            }
        }
尾声
同样我们来编写一个函数来打印出DFA。
 void printDFA()
        {
            printf("---------- DFA Start ----------n");
            set tmp;
            for (typename set::const_iterator i = dfa_Edges.begin(), m = dfa_Edges.end(); i != m; ++i)
            {
                printf("%03d -> %03d", i->pFrom->idx, i->pTo->idx);
                switch (i->edgeType())
                {
                case DFA_Edge::TChar:
                    printf("(%c)", i->data.char_value);
                    break;
                case DFA_Edge::TString:
                    printf("(%s)", i->data.string_value.c_str());
                    break;
                default:
                    break;
                }
                if (i->isNot()) printf("(not)");
                printf("n");
                tmp.insert(i->pFrom);
                tmp.insert(i->pTo);
            }
            printf("start: %03d -> ends: ", pDFAStart->idx);
            for (typename set::const_iterator i = pDFAEnds.begin(), m = pDFAEnds.end(); i != m; ++i)
            {
                printf("%03d ", (*i)->idx);
            }
            printf("n");
#if DEBUG_LEVEL == 3
            printf("-------------------------------n");
            for (typename set::const_iterator i = tmp.begin(), m = tmp.end(); i != m; ++i)
            {
                printf("State: %03dn", (*i)->idx);
                for (typename set::const_iterator j = (*i)->content.begin(), n = (*i)->content.end(); j != n; ++j)
                {
                    printf("%03d ", (*j)->idx);
                }
                printf("n");
            }
#endif
            printf("----------- DFA End -----------n");
        }
最后我们加入测试代码
Rule_Type::Context context;
Rule_Type a('a', context), b('b', context), d('d', context);
Rule_Type result = (a - d).opt() + (+b | !(a + b));
result.buildDFA();
#ifdef _DEBUG
result.printEpsilonNFA();
result.printDFA();
#endif
可打印出如下内容
DFA
画成图如下
DFA图
Categories
不学无术

re -> NFA 正则表达式->不确定自动机

文章来自http://www.360doc.com/content/09/0219/10/98111_2586955.shtml
以及http://hi.baidu.com/tcet030840zxp/item/c923fe885ddd0329100ef3ec

最近得做一些跟自动机有关的东东,其中一部分可以简要地看作是由一套正则文法生成状态自动机的过程。

什么是正则表达式?

首先我们看看什么是正则表达式。这个东东呢,一般用于描述一个字符串的集合——直接说就是一个正则表达式可能可以匹配一大堆字符串,而这一大堆字符串可以形成一个集合,它们的共同特征就是可以被这个正则表达式匹配。就像去死去死团,但是不同的是去死去死团的团员的共同特征是不被任何异性所匹配——但是这没关系,我们不妨取去死去死团的补集就行了。
反正正则表达是很好啦,因为你只要用一点点在脏话里,就可以骂好多好多人,比如:

Mar(y|k|cus) is son of bitch.

真是非常de省力,唯一的缺点是可能对方不知道你在说什么。
好了,从上面我们可以看出正则表达式中的两个基本结构:

  • 连结 (Concatenation),比如 bitch,由b, i, t, c, h连接而成
  • 联合 (Union),比如 y|k|cus,可以认为是y或k或者cus

下面是第三个基本结构,被称为Kleene star (或者 Kleene 闭包)的。因为这个操作是Stephen Cole Kleene发明的。啊啊,其实正则表达式这个东西就是Kleene发明的。这个同学真是非常的牛B,因为他是更加牛B的 阿隆佐 – 丘奇 ( Alonzo Church )——历史上和阿兰 – 图灵 ( Alan Turing ) 并称的人物——的学生。有多牛B呢,这个Kleene还和他的老师,还有图灵,就递归论发表了论文,奠定了可计算理论的根基。啊哈哈哈,真是牛B啊。
嗯,所谓Kleene Star的例子就是这样的。

  • Kleene Star,比如a*,可以接受空串和若干个a连结组成的串

当然咯,还有一些别的操作,比如我们知道的+,?,集合[]等等,但是这些操作都可以通过上面三个基本操作的组合来完成。
比如+,a+可以认为是aa*

什么是NFA?

要说NFA嘛,我得先说说DFA。所谓DFA,就是Deterministic Finite state Automata的简称。是状态机的一种。通俗的说,就是一大堆状态的集合,里面有一个初始状态和若干终止状态,每个状态可以有若干个输出边前往别的状态。但是要求每个状态的同一种输出边至多只有一个,所以自动机被称为是”Deterministic”的。
比如下面这个例子:
表述的是一个电灯de开关,这个开关每按一下就从’开’状态转换到’关’状态,或者从’关’状态转换到’开’状态。而为了从环保角度出发,在’关’状态才被认为是终止态。
dfa
上面的自动机呢,就可以描述这个灯泡的行为模式,或者说可以描述电灯的状态转换过程。输出边就是’开’或者’关’的动作,或者说这个灯泡的开关,只接受这两种动作:“Trun On”,“Trun Off”。而”Trun On”动作只会导致灯的状态变成“On”,“Trun Off”动作只会导致灯的状态变成“Off”,这是确定的,你的外婆都可以预料到的。所以说DFA是确定有限状态自动机。
现在可以说NFA了。这个NFA嘛,全称是Non-deterministic Finite state Automata。也是状态自动机的一种。确切地说,刚才的DFA是NFA的一个子集。和DFA唯一的区别就是他是”Non-deterministic”的,哈,非确定的,每个状态的同一种输出边可以不止一个。
还是用刚才的例子。现在假设我们的电灯有一种新的状态咯~:坏掉了。灯丝被过大的电流烧断了,听上去遭透了,因为一”Trun On”就得准备换灯泡了:
nfa
但是我们没法确定的知道哪一次Trun On会导致灯泡坏掉,使得灯泡进入”Down”状态的那次“开”操作看上去跟你昨天开灯的那次操作一模一样(严格的说,每一次点亮灯泡都会导致灯丝的状态发生变化,但是在此简化了)
所以从状态”Off”出来的输出边中,”Trun On”有两条,这就导致没法根据当前状态和输出边确定下一状态,这就是为什么称为非确定性有限自动机的原因。

如何转换?

刚才Shellex说了,正则表达式有三种基本结构。如果能先将这三种基本结构转换成对应的NFA,然后在用这三种基本结构去拼装成完整的NFA是不是很省力呢?
下面就是三种基本正则表达式的NFA
ab:
g_basic_a_concat_b_blog
a*:
g_basic_a_star_blog
a|b:
g_basic_a_union_b_blog
里面出现了一种叫“None”的边。这个不代表这个边是字面上的“None”,而是指这个边是个空边。也就是说任何“动作”都可以从这个边进入下一个状态。它的学名叫 epsilon 边,一般表示成’ε’,Shellex这里表示成“None”了。
下面我们来考虑正则表达式到NFA转换。给出一个正则串的输入,得到一个NFA的输出。被广泛采用的是Thompson Algorithm,也就是所谓的子集算法。该算法的发明人应该就是写ed编辑器的那个Thompson大牛。该算法的实现和算术表达式的求值非常的类似,需要一个符号栈存放操作符,一个自动机栈存放生成的自动机。算法结束后,可以从自动机栈中Pop一个最终的结果。
比如对于正则表达式(a|b)*cd,求值过程如下:

PUSH a To automaton stack
PUSH b To automaton stack
UNION
STAR
PUSH c To automaton stack
CONCAT
PUSH d To automaton stack
CONCAT
POP result

里面的UNION,STAR 和 CONCAT就是三种基本结构的生成操作了。而这三种基本操作的实现是这样的:
Star:

POP T from automaton stack
CREATE state A, B
ADD transition from A to B with 'ε'
ADD transition from A to T.entry with 'ε'
ADD transition from T.exit to A with 'ε'
ADD transition from T.exit to B with 'ε'
ADD state A, B to T
PUSH T to automaton stack

Concat:

POP F, S from automaton stack
ADD transition from F.exit to S.entry with 'ε'
JOIN S to F
SET F.exit = S.exit
SET F.inputSet += S.inputSet
PUSH F to automaton stack

Union:

POP F, S from automaton stack
CREATE state A, B
ADD transition from A to F.entry with 'ε'
ADD transition from A to S.entry with 'ε'
ADD transition from T.exit to B with 'ε'
ADD transition from T.exit to B with 'ε'
JOIN S to F
ADD state A, B to T
SET F.exit = S.exit
SET F.inputSet += S.inputSet
PUSH F to automaton stack
/* Regular expression implementation.
 * Supports only ( | ) * + ?.  No escapes.
 * Compiles to NFA and then simulates NFA
 * using Thompson's algorithm.
 *
 * See also http://swtch.com/~rsc/regexp/ and
 * Thompson, Ken.  Regular Expression Search Algorithm,
 * Communications of the ACM 11(6) (June 1968), pp. 419-422.
 * 
 * Copyright (c) 2007 Russ Cox.
 * Can be distributed under the MIT license, see bottom of file.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/*
 * Convert infix regexp re to postfix notation.
 * Insert . as explicit concatenation operator.
 * Cheesy parser, return static buffer.
 */
char*
re2post(char *re)
{
	int nalt, natom;
	static char buf[8000];
	char *dst;
	struct {
		int nalt;
		int natom;
	} paren[100], *p;
	p = paren;
	dst = buf;
	nalt = 0;
	natom = 0;
	if(strlen(re) >= sizeof buf/2)
		return NULL;
	for(; *re; re++){
		switch(*re){
		case '(':
			if(natom > 1){
				--natom;
				*dst++ = '.';
			}
			if(p >= paren+100)
				return NULL;
			p->nalt = nalt;
			p->natom = natom;
			p++;
			nalt = 0;
			natom = 0;
			break;
		case '|':
			if(natom == 0)
				return NULL;
			while(--natom > 0)
				*dst++ = '.';
			nalt++;
			break;
		case ')':
			if(p == paren)
				return NULL;
			if(natom == 0)
				return NULL;
			while(--natom > 0)
				*dst++ = '.';
			for(; nalt > 0; nalt--)
				*dst++ = '|';
			--p;
			nalt = p->nalt;
			natom = p->natom;
			natom++;
			break;
		case '*':
		case '+':
		case '?':
			if(natom == 0)
				return NULL;
			*dst++ = *re;
			break;
		default:
			if(natom > 1){
				--natom;
				*dst++ = '.';
			}
			*dst++ = *re;
			natom++;
			break;
		}
	}
	if(p != paren)
		return NULL;
	while(--natom > 0)
		*dst++ = '.';
	for(; nalt > 0; nalt--)
		*dst++ = '|';
	*dst = 0;
	return buf;
}
/*
 * Represents an NFA state plus zero or one or two arrows exiting.
 * if c == Match, no arrows out; matching state.
 * If c == Split, unlabeled arrows to out and out1 (if != NULL).
 * If c < 256, labeled arrow with character c to out.
 */
enum
{
	Match = 256,
	Split = 257
};
typedef struct State State;
struct State
{
	int c;
	State *out;
	State *out1;
	int lastlist;
};
State matchstate = { Match };	/* matching state */
int nstate;
/* Allocate and initialize State */
State*
state(int c, State *out, State *out1)
{
	State *s;
	nstate++;
	s = malloc(sizeof *s);
	s->lastlist = 0;
	s->c = c;
	s->out = out;
	s->out1 = out1;
	return s;
}
/*
 * A partially built NFA without the matching state filled in.
 * Frag.start points at the start state.
 * Frag.out is a list of places that need to be set to the
 * next state for this fragment.
 */
typedef struct Frag Frag;
typedef union Ptrlist Ptrlist;
struct Frag
{
	State *start;
	Ptrlist *out;
};
/* Initialize Frag struct. */
Frag
frag(State *start, Ptrlist *out)
{
	Frag n = { start, out };
	return n;
}
/*
 * Since the out pointers in the list are always 
 * uninitialized, we use the pointers themselves
 * as storage for the Ptrlists.
 */
union Ptrlist
{
	Ptrlist *next;
	State *s;
};
/* Create singleton list containing just outp. */
Ptrlist*
list1(State **outp)
{
	Ptrlist *l;
	l = (Ptrlist*)outp;
	l->next = NULL;
	return l;
}
/* Patch the list of states at out to point to start. */
void
patch(Ptrlist *l, State *s)
{
	Ptrlist *next;
	for(; l; l=next){
		next = l->next;
		l->s = s;
	}
}
/* Join the two lists l1 and l2, returning the combination. */
Ptrlist*
append(Ptrlist *l1, Ptrlist *l2)
{
	Ptrlist *oldl1;
	oldl1 = l1;
	while(l1->next)
		l1 = l1->next;
	l1->next = l2;
	return oldl1;
}
/*
 * Convert postfix regular expression to NFA.
 * Return start state.
 */
State*
post2nfa(char *postfix)
{
	char *p;
	Frag stack[1000], *stackp, e1, e2, e;
	State *s;
	// fprintf(stderr, "postfix: %sn", postfix);
	if(postfix == NULL)
		return NULL;
	#define push(s) *stackp++ = s
	#define pop() *--stackp
	stackp = stack;
	for(p=postfix; *p; p++){
		switch(*p){
		default:
			s = state(*p, NULL, NULL);
			push(frag(s, list1(&s->out)));
			break;
		case '.':	/* catenate */
			e2 = pop();
			e1 = pop();
			patch(e1.out, e2.start);
			push(frag(e1.start, e2.out));
			break;
		case '|':	/* alternate */
			e2 = pop();
			e1 = pop();
			s = state(Split, e1.start, e2.start);
			push(frag(s, append(e1.out, e2.out)));
			break;
		case '?':	/* zero or one */
			e = pop();
			s = state(Split, e.start, NULL);
			push(frag(s, append(e.out, list1(&s->out1))));
			break;
		case '*':	/* zero or more */
			e = pop();
			s = state(Split, e.start, NULL);
			patch(e.out, s);
			push(frag(s, list1(&s->out1)));
			break;
		case '+':	/* one or more */
			e = pop();
			s = state(Split, e.start, NULL);
			patch(e.out, s);
			push(frag(e.start, list1(&s->out1)));
			break;
		}
	}
	e = pop();
	if(stackp != stack)
		return NULL;
	patch(e.out, &matchstate);
	return e.start;
#undef pop
#undef push
}
typedef struct List List;
struct List
{
	State **s;
	int n;
};
List l1, l2;
static int listid;
void addstate(List*, State*);
void step(List*, int, List*);
/* Compute initial state list */
List*
startlist(State *start, List *l)
{
	l->n = 0;
	listid++;
	addstate(l, start);
	return l;
}
/* Check whether state list contains a match. */
int
ismatch(List *l)
{
	int i;
	for(i=0; i<l->n; i++)
		if(l->s[i] == &matchstate)
			return 1;
	return 0;
}
/* Add s to l, following unlabeled arrows. */
void
addstate(List *l, State *s)
{
	if(s == NULL || s->lastlist == listid)
		return;
	s->lastlist = listid;
	if(s->c == Split){
		/* follow unlabeled arrows */
		addstate(l, s->out);
		addstate(l, s->out1);
		return;
	}
	l->s[l->n++] = s;
}
/*
 * Step the NFA from the states in clist
 * past the character c,
 * to create next NFA state set nlist.
 */
void
step(List *clist, int c, List *nlist)
{
	int i;
	State *s;
	listid++;
	nlist->n = 0;
	for(i=0; i<clist->n; i++){
		s = clist->s[i];
		if(s->c == c)
			addstate(nlist, s->out);
	}
}
/* Run NFA to determine whether it matches s. */
int
match(State *start, char *s)
{
	int i, c;
	List *clist, *nlist, *t;
	clist = startlist(start, &l1);
	nlist = &l2;
	for(; *s; s++){
		c = *s & 0xFF;
		step(clist, c, nlist);
		t = clist; clist = nlist; nlist = t;	/* swap clist, nlist */
	}
	return ismatch(clist);
}
int
main(int argc, char **argv)
{
	int i;
	char *post;
	State *start;
	if(argc < 3){
		fprintf(stderr, "usage: nfa regexp string...n");
		return 1;
	}
	post = re2post(argv[1]);
	if(post == NULL){
		fprintf(stderr, "bad regexp %sn", argv[1]);
		return 1;
	}
	start = post2nfa(post);
	if(start == NULL){
		fprintf(stderr, "error in post2nfa %sn", post);
		return 1;
	}
	l1.s = malloc(nstate*sizeof l1.s[0]);
	l2.s = malloc(nstate*sizeof l2.s[0]);
	for(i=2; i<argc; i++)
		if(match(start, argv[i]))
			printf("%sn", argv[i]);
	return 0;
}
/*
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the
 * Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall
 * be included in all copies or substantial portions of the
 * Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
 * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS
 * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
Categories
不学无术

2013 数模美赛(MCM) 一等奖论文 一篇

2016.1 链接已更新

其实就是自己组的啦~有需要的拿去看吧,还有很多需要完善的地方,拿了M奖也很是惊喜,哈哈~
Team #18836 The Ultimate Brownie Pan
 
 

Categories
不学无术

B+树的一些资料,留着备用

近期数据库老师要求写一个B+树,还是要存储在磁盘上的,暂时收集到下列资料:

Categories
不学无术

1023. Have Fun with Numbers (20)

Notice that the number 123456789 is a 9-digit number consisting exactly the numbers from 1 to 9, with no duplication. Double it we will obtain 246913578, which happens to be another 9-digit number consisting exactly the numbers from 1 to 9, only in a different permutation. Check to see the result if we double it again!
Now you are suppose to check if there are more numbers with this property. That is, double a given number with k digits, you are to tell if the resulting number consists of only a permutation of the digits in the original number.
Input Specification:
Each input file contains one test case. Each case contains one positive integer with no more than 20 digits.
Output Specification:
For each test case, first print in a line “Yes” if doubling the input number gives a number that consists of only a permutation of the digits in the original number, or “No” if not. Then in the next line, print the doubled number.
Sample Input:

1234567899

Sample Output:

Yes
2469135798

====================================
恩恩,having fun….
这道题的险恶用心在于..
int最大值 2147483647
longlong 最大值 9223372036854775807
都不满足20位的标准…因此需要自己手工做乘法计算~
其实乘法也是很好算的嘛~喵
还好时间给的充裕…
====================================

#include 
using namespace std;
char digs_in[20];
int digs_out[30];
short old_nums[10];
short new_nums[10];
int main()
{
	cin >> digs_in;
	//find ''
	int pos = 0;
	while(true)
	{
		if(digs_in[pos++] == '')
			break;
	}
	pos--;
	//手工做*2...
	int r = 0;
	int d = 0;
	int count = 0;
	while (pos--)
	{
		d = (int)digs_in[pos] - 0x30;  //ASCII -> digit
		old_nums[d] ++;
		d = d << 1; //d*=2
		d += r;
		r = d / 10;
		d = d % 10;
		digs_out[count++] = d;
		new_nums[d] ++;
	}
	if( r > 0)
	{
		//最高位
		digs_out[count] = r;
		new_nums[r] ++;
	}
	else
		count --;
	bool flag = true;
	for(int i=0; i<10; i++)
	{
		if(old_nums[i] != new_nums[i])
		{
			flag = false;
			break;
		}
	}
	if(flag)
	{
		cout << "Yes" << endl;
	}
	else
	{
		cout << "No" << endl;
	}
	for(int i=count; i>=0; i--)
		cout << digs_out[i];
	return 0;
}
Categories
不学无术

linux环境下pthread链接报错的解决

本人对linux环境很不熟悉,今天做操作系统作业要在linux下用信号量以及pthread编程,使用codeblocks这个IDE,然后链接报错
/tmp/ccMNPEfl.o:在函数‘init_semaphores()’中:
source.cpp:(.text+0x212):对‘sem_init’未定义的引用
source.cpp:(.text+0x22e):对‘sem_init’未定义的引用
source.cpp:(.text+0x24a):对‘sem_init’未定义的引用
/tmp/ccMNPEfl.o:在函数‘ProducerProcess(void*)’中:
source.cpp:(.text+0x2a8):对‘sem_wait’未定义的引用
source.cpp:(.text+0x2b4):对‘sem_wait’未定义的引用
source.cpp:(.text+0x31c):对‘sem_post’未定义的引用
source.cpp:(.text+0x328):对‘sem_post’未定义的引用
/tmp/ccMNPEfl.o:在函数‘ConsumerProcess(void*)’中:
source.cpp:(.text+0x34c):对‘sem_wait’未定义的引用
source.cpp:(.text+0x358):对‘sem_wait’未定义的引用
source.cpp:(.text+0x3bd):对‘sem_post’未定义的引用
source.cpp:(.text+0x3c9):对‘sem_post’未定义的引用
/tmp/ccMNPEfl.o:在函数‘init_threads()’中:
source.cpp:(.text+0x417):对‘pthread_create’未定义的引用
source.cpp:(.text+0x431):对‘pthread_join’未定义的引用
source.cpp:(.text+0x45c):对‘pthread_create’未定义的引用
source.cpp:(.text+0x476):对‘pthread_join’未定义的引用
collect2: 错误: ld 返回 1
后来查了半天发现是链接器要加上参数 -pthread
记录一下,说不定以后又忘了呢。。~

Categories
不学无术 木有技术

Linux下多线程pthread的使用以及信号量semaphore相关

摘自:http://www.china-pub.com 作者: 姚继锋 (2001-08-11 09:05:00)
关键字:Linux 多线程 Pthread semaphore

简单的多线程编程
Linux
系统下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a。顺便说一下,Linuxpthread的实现是通过系统调用clone()来实现的。clone()是Linux所特有的系统调用,它的使用方式类似fork,关于clone()的详细情况,有兴趣的读者可以去查看有关文档说明。下面我们展示一个最简单的多线程程序 example1.c
<pre>
/* example.c*/
#include <stdio.h>
#include <pthread.h>
void thread(void)
{
int i;
for( i = 0;i < 3; i++ )
printf(“This is a pthread.n”);
}
int main(void)
{
pthread_t id;
int i,ret;
ret = pthread_create( &id, NULL, (void *)thread, NULL );
if ( ret!=0 ) {
printf (“Create pthread error!n”);
exit (1);
}
for( i = 0; i < 3; i++ )
printf(“This is the main process.n”);
pthread_join(id,NULL);
return (0);
}
</pre>
我们编译此程序:
gcc example1.c -lpthread -o example1
运行example1,我们得到如下结果:
This is the main process.
This is a pthread.
This is the main process.
This is the main process.
This is a pthread.
This is a pthread.
再次运行,我们可能得到如下结果:
This is a pthread.
This is the main process.
This is a pthread.
This is the main process.
This is a pthread.
This is the main process.

前后两次结果不一样,这是两个线程争夺CPU资源的结果。上面的示例中,我们使用到了两个函数,  
pthread_create
pthread_join,并声明了一个pthread_t型的变量。
pthread_t
在头文件/usr/include/bits/pthreadtypes.h中定义:
typedef unsigned long int pthread_t;
它是一个线程的标识符。函数pthread_create用来创建一个线程,它的原型为:
extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr,
void *(*__start_routine) (void *), void *__arg));
第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。这里,我们的函数thread不需要参数,所以最后一个参数设为空指针。第二个参数我们也设为空指针,这样将生成默认属性的线程。对线程属性的设定和修改我们将在下一节阐述。当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAINEINVAL。前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。创建线程成功后,新创建的线程则运行参数三和参数四确定的函数,原来的线程则继续运行下一行代码。
函数pthread_join用来等待一个线程的结束。函数原型为:
extern int pthread_join __P ((pthread_t __th, void **__thread_return));
第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储被等待线程的返回值。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。一个线程的结束有两种途径,一种是象我们上面的例子一样,函数结束了,调用它的线程也就结束了;另一种方式是通过函数pthread_exit来实现。它的函数原型为:
extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));
唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给 thread_return。最后要说明的是,一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH
信号量
信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。当公共资源增加时,调用函数sem_post()增加信号量。只有当信号量值大于0时,才能使用公共资源,使用后,函数sem_wait()减少信号量。函数sem_trywait()和函数pthread_ mutex_trylock()起同样的作用,它是函数sem_wait()的非阻塞版本。下面我们逐个介绍和信号量有关的一些函数,它们都在头文件 /usr/include/semaphore.h中定义。
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:
extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));
sem
为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。
函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。
函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。
函数sem_destroy(sem_t *sem)用来释放信号量sem
下面我们来看一个使用信号量的例子。在这个例子中,一共有4个线程,其中两个线程负责从文件读取数据到公共的缓冲区,另两个线程从缓冲区读取数据作不同的处理(加和乘运算)。
/* File sem.c */
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#define MAXSTACK 100

int stack[MAXSTACK][2];
int size = 0;
sem_t sem;
/* 从文件1.dat读取数据,每读一次,信号量加一*/
void ReadData1( void )
{
FILE *fp = fopen( “1.dat”, “r” );

while ( !feof( fp ) )
{
fscanf( fp, “%d %d”, &stack[size][0], &stack[size][1] );
sem_post( &sem );
++size;
}
fclose(fp);
}
/*从文件2.dat读取数据*/
void ReadData2( void )
{
FILE *fp=fopen(“2.dat”,”r”);

while ( !feof( fp ) )
{
fscanf(fp,”%d %d”,&stack[size][0],&stack[size][1]);
sem_post(&sem);
++size;
}
fclose(fp);
}
/*阻塞等待缓冲区有数据,读取数据后,释放空间,继续等待*/
void HandleData1( void )
{
while( 1 )
{
sem_wait( &sem );
printf( “Plus:%d+%d=%dn”, stack[size][0], stack[size][1],
stack[size][0]+stack[size][1] );
–size;
}
}

void HandleData2(void)
{
while ( 1 )
{
sem_wait( &sem );
printf( “Multiply:%d*%d=%dn”, stack[size][0],stack[size][1],
stack[size][0]*stack[size][1] );
–size;
}
}
int main(void)
{
pthread_t t1,t2,t3,t4;
sem_init( &sem, 0, 0 );
pthread_create( &t1, NULL, (void *)HandleData1, NULL);
pthread_create( &t2, NULL, (void *)HandleData2, NULL);
pthread_create( &t3, NULL, (void *)ReadData1,     NULL);
pthread_create( &t4, NULL, (void *)ReadData2,    NULL);
/* 防止程序过早退出,让它在此无限期等待*/
pthread_join( t1,NULL );
}

Linux下,我们用命令gcc -lpthread sem.c -o sem生成可执行文件sem。 我们事先编辑好数据文件1.dat2.dat,假设它们的内容分别为1 2 3 4 5 6 7 8 9 10-1 -2 -3 -4 -5 -6 -7 -8 -9 -10 ,我们运行sem,得到如下的结果:
Multiply:-1*-2=2
Plus:-1+-2=-3
Multiply:9*10=90
Plus:-9+-10=-19
Multiply:-7*-8=56
Plus:-5+-6=-11
Multiply:-3*-4=12
Plus:9+10=19
Plus:7+8=15
Plus:5+6=11

从中我们可以看出各个线程间的竞争关系。而数值并未按我们原先的顺序显示出来这是由于size这个数值被各个线程任意修改的缘故。这也往往是多线程编程要注意的问题。

Categories
不学无术 木有技术

[转载]跟我一起写 Makefile

本文来源:

http://www.chinaunix.net/old_jh/23/408225.html

 
陈皓
概述
——
什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。
因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
现在讲述如何写makefile的文章比较少,这是我想写这篇文章的原因。当然,不同产商的make各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对GNU的make进行讲述,我的环境是RedHat Linux 8.0,make的版本是3.80。必竟,这个make是应用最为广泛的,也是用得最多的。而且其还是最遵循于IEEE 1003.2-1992 标准的(POSIX.2)。
在这篇文档中,将以C/C++的源码作为我们基础,所以必然涉及一些关于C/C++的编译的知识,相关于这方面的内容,还请各位查看相关的编译器的文档。这里所默认的编译器是UNIX下的GCC和CC。